Started transition to SDL3 (audio working)
This commit is contained in:
parent
1723651511
commit
0471d11909
|
@ -12,12 +12,12 @@ include(DownloadExternals)
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl3/qt as dependent options.
|
||||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
# OFF by default, but if ENABLE_SDL3 and MSVC are true then ON
|
||||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
|
option(ENABLE_SDL3 "Enable the SDL3 frontend" ON)
|
||||||
CMAKE_DEPENDENT_OPTION(SUDACHI_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
|
CMAKE_DEPENDENT_OPTION(SUDACHI_USE_BUNDLED_SDL3 "Download bundled SDL3 binaries" ON "ENABLE_SDL3;MSVC" OFF)
|
||||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
# On Linux system SDL3 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||||
CMAKE_DEPENDENT_OPTION(SUDACHI_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
|
CMAKE_DEPENDENT_OPTION(SUDACHI_USE_EXTERNAL_SDL3 "Compile external SDL3" ON "ENABLE_SDL3;NOT MSVC" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||||
|
|
||||||
|
@ -527,32 +527,32 @@ if(ENABLE_QT)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the sudachi_find_package
|
# find SDL3 exports a bunch of variables that are needed, so its easier to do this outside of the sudachi_find_package
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
if (SUDACHI_USE_BUNDLED_SDL2)
|
if (SUDACHI_USE_BUNDLED_SDL3)
|
||||||
# Detect toolchain and platform
|
# Detect toolchain and platform
|
||||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||||
set(SDL2_VER "SDL2-2.28.2")
|
set(SDL3_VER "SDL3-3.1.2")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable SUDACHI_USE_BUNDLED_SDL2 and provide your own.")
|
message(FATAL_ERROR "No bundled SDL3 binaries for your toolchain. Disable SUDACHI_USE_BUNDLED_SDL3 and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (DEFINED SDL2_VER)
|
if (DEFINED SDL3_VER)
|
||||||
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
|
download_bundled_external("sdl3/" ${SDL3_VER} SDL3_PREFIX)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(SDL2_FOUND YES)
|
set(SDL3_FOUND YES)
|
||||||
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
|
set(SDL3_INCLUDE_DIR "${SDL3_PREFIX}/include" CACHE PATH "Path to SDL3 headers")
|
||||||
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
|
set(SDL3_LIBRARY "${SDL3_PREFIX}/lib/x64/SDL3.lib" CACHE PATH "Path to SDL3 library")
|
||||||
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
|
set(SDL3_DLL_DIR "${SDL3_PREFIX}/lib/x64/" CACHE PATH "Path to SDL3.dll")
|
||||||
|
|
||||||
add_library(SDL2::SDL2 INTERFACE IMPORTED)
|
add_library(SDL3::SDL3 INTERFACE IMPORTED)
|
||||||
target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}")
|
target_link_libraries(SDL3::SDL3 INTERFACE "${SDL3_LIBRARY}")
|
||||||
target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
target_include_directories(SDL3::SDL3 INTERFACE "${SDL3_INCLUDE_DIR}")
|
||||||
elseif (SUDACHI_USE_EXTERNAL_SDL2)
|
elseif (SUDACHI_USE_EXTERNAL_SDL3)
|
||||||
message(STATUS "Using SDL2 from externals.")
|
message(STATUS "Using SDL3 from externals.")
|
||||||
else()
|
else()
|
||||||
find_package(SDL2 2.26.4 REQUIRED)
|
find_package(SDL3 3.1.2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
function(copy_sudachi_SDL_deps target_dir)
|
function(copy_sudachi_SDL_deps target_dir)
|
||||||
include(WindowsCopyFiles)
|
include(WindowsCopyFiles)
|
||||||
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
||||||
windows_copy_files(${target_dir} ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
|
windows_copy_files(${target_dir} ${SDL3_DLL_DIR} ${DLL_DEST} SDL3.dll)
|
||||||
endfunction(copy_sudachi_SDL_deps)
|
endfunction(copy_sudachi_SDL_deps)
|
||||||
|
|
|
@ -6,7 +6,7 @@ set(CMAKE_SYSTEM_NAME Windows)
|
||||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||||
set(SDL2_PATH ${MINGW_PREFIX})
|
set(SDL3_PATH ${MINGW_PREFIX})
|
||||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||||
|
|
||||||
# Specify the cross compiler
|
# Specify the cross compiler
|
||||||
|
|
|
@ -9,7 +9,7 @@ set(CMAKE_HOST_WIN32 TRUE)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||||
set(SDL2_PATH ${MINGW_PREFIX})
|
set(SDL3_PATH ${MINGW_PREFIX})
|
||||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||||
|
|
||||||
# Specify the cross compiler
|
# Specify the cross compiler
|
||||||
|
|
|
@ -62,8 +62,8 @@ if (ENABLE_LIBUSB AND NOT TARGET libusb::usb)
|
||||||
add_subdirectory(libusb)
|
add_subdirectory(libusb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SDL2
|
# SDL3
|
||||||
if (SUDACHI_USE_EXTERNAL_SDL2)
|
if (SUDACHI_USE_EXTERNAL_SDL3)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
# Sudachi itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
# Sudachi itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit cc016b0046d563287f0aa9f09b958b5e70d43696
|
Subproject commit 84cb065da2fcae9482d2ab7702d8bc4218ff80ed
|
|
@ -201,7 +201,7 @@ if (SUDACHI_TESTS)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
add_subdirectory(sudachi_cmd)
|
add_subdirectory(sudachi_cmd)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@ android {
|
||||||
cmake {
|
cmake {
|
||||||
arguments(
|
arguments(
|
||||||
"-DENABLE_QT=0", // Don't use QT
|
"-DENABLE_QT=0", // Don't use QT
|
||||||
"-DENABLE_SDL2=0", // Don't use SDL
|
"-DENABLE_SDL3=0", // Don't use SDL
|
||||||
"-DENABLE_WEB_SERVICE=0", // Don't use telemetry
|
"-DENABLE_WEB_SERVICE=0", // Don't use telemetry
|
||||||
"-DBUNDLE_SPEEX=ON",
|
"-DBUNDLE_SPEEX=ON",
|
||||||
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
||||||
|
|
|
@ -382,7 +382,7 @@ bg_green =
|
||||||
# Which audio output engine to use.
|
# Which audio output engine to use.
|
||||||
# auto (default): Auto-select
|
# auto (default): Auto-select
|
||||||
# cubeb: Cubeb audio engine (if available)
|
# cubeb: Cubeb audio engine (if available)
|
||||||
# sdl2: SDL2 audio engine (if available)
|
# sdl3: SDL3 audio engine (if available)
|
||||||
# null: No audio output
|
# null: No audio output
|
||||||
output_engine =
|
output_engine =
|
||||||
|
|
||||||
|
|
|
@ -241,14 +241,14 @@ if (ENABLE_CUBEB)
|
||||||
target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
|
target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_sources(audio_core PRIVATE
|
target_sources(audio_core PRIVATE
|
||||||
sink/sdl2_sink.cpp
|
sink/sdl3_sink.cpp
|
||||||
sink/sdl2_sink.h
|
sink/sdl3_sink.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "audio_core/common/common.h"
|
#include "audio_core/common/common.h"
|
||||||
#include "audio_core/sink/sdl2_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#include "audio_core/sink/sink_stream.h"
|
#include "audio_core/sink/sink_stream.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
@ -35,6 +35,29 @@ public:
|
||||||
system_channels = system_channels_;
|
system_channels = system_channels_;
|
||||||
device_channels = device_channels_;
|
device_channels = device_channels_;
|
||||||
|
|
||||||
|
SDL_AudioSpec spec{.format = SDL_AUDIO_S16,
|
||||||
|
.channels = static_cast<u8>(device_channels),
|
||||||
|
.freq = TargetSampleRate};
|
||||||
|
|
||||||
|
std::string device_name{output_device};
|
||||||
|
SDL_AudioDeviceID devid = SDL_AUDIO_DEVICE_DEFAULT_OUTPUT;
|
||||||
|
if (type == StreamType::In) {
|
||||||
|
device_name = input_device;
|
||||||
|
devid = SDL_AUDIO_DEVICE_DEFAULT_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = SDL_OpenAudioDevice(devid, &spec);
|
||||||
|
|
||||||
|
if (device == 0) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_Audio, "Opening SDL stream for: {}", SDL_GetAudioDeviceName(device));
|
||||||
|
|
||||||
|
stream = SDL_OpenAudioDeviceStream(device, &spec, &SDLSinkStream::DataCallback, this);
|
||||||
|
|
||||||
|
/*
|
||||||
SDL_AudioSpec spec;
|
SDL_AudioSpec spec;
|
||||||
spec.freq = TargetSampleRate;
|
spec.freq = TargetSampleRate;
|
||||||
spec.channels = static_cast<u8>(device_channels);
|
spec.channels = static_cast<u8>(device_channels);
|
||||||
|
@ -66,6 +89,7 @@ public:
|
||||||
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
||||||
" samples {}",
|
" samples {}",
|
||||||
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
|
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +109,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop();
|
Stop();
|
||||||
SDL_ClearQueuedAudio(device);
|
SDL_ClearAudioStream(stream);
|
||||||
SDL_CloseAudioDevice(device);
|
SDL_CloseAudioDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +125,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
paused = false;
|
paused = false;
|
||||||
SDL_PauseAudioDevice(device, 0);
|
SDL_ResumeAudioDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,7 +136,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SignalPause();
|
SignalPause();
|
||||||
SDL_PauseAudioDevice(device, 1);
|
SDL_PauseAudioDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -124,7 +148,8 @@ private:
|
||||||
* @param stream - Buffer of samples to be filled or read.
|
* @param stream - Buffer of samples to be filled or read.
|
||||||
* @param len - Length of the stream in bytes.
|
* @param len - Length of the stream in bytes.
|
||||||
*/
|
*/
|
||||||
static void DataCallback(void* userdata, Uint8* stream, int len) {
|
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
|
||||||
|
int total_amount) {
|
||||||
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
||||||
|
|
||||||
if (!impl) {
|
if (!impl) {
|
||||||
|
@ -133,7 +158,7 @@ private:
|
||||||
|
|
||||||
const std::size_t num_channels = impl->GetDeviceChannels();
|
const std::size_t num_channels = impl->GetDeviceChannels();
|
||||||
const std::size_t frame_size = num_channels;
|
const std::size_t frame_size = num_channels;
|
||||||
const std::size_t num_frames{len / num_channels / sizeof(s16)};
|
const std::size_t num_frames{total_amount / num_channels / sizeof(s16)};
|
||||||
|
|
||||||
if (impl->type == StreamType::In) {
|
if (impl->type == StreamType::In) {
|
||||||
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
|
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
|
||||||
|
@ -147,6 +172,7 @@ private:
|
||||||
|
|
||||||
/// SDL device id of the opened input/output device
|
/// SDL device id of the opened input/output device
|
||||||
SDL_AudioDeviceID device{};
|
SDL_AudioDeviceID device{};
|
||||||
|
SDL_AudioStream* stream = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
|
@ -220,18 +246,34 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int device_count = SDL_GetNumAudioDevices(capture);
|
switch (capture) {
|
||||||
for (int i = 0; i < device_count; ++i) {
|
case false: {
|
||||||
if (const char* name = SDL_GetAudioDeviceName(i, capture)) {
|
int count = 0;
|
||||||
|
SDL_GetAudioOutputDevices(&count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (const char* name = SDL_GetAudioDeviceName(i)) {
|
||||||
device_list.emplace_back(name);
|
device_list.emplace_back(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case true: {
|
||||||
|
int count = 0;
|
||||||
|
SDL_GetAudioCaptureDevices(&count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (const char* name = SDL_GetAudioDeviceName(i)) {
|
||||||
|
device_list.emplace_back(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return device_list;
|
return device_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSDLSuitable() {
|
bool IsSDLSuitable() {
|
||||||
#if !defined(HAVE_SDL2)
|
#if !defined(HAVE_SDL3)
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
// Check SDL can init
|
// Check SDL can init
|
||||||
|
@ -246,6 +288,7 @@ bool IsSDLSuitable() {
|
||||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||||
|
|
||||||
// Check we can open a device with standard parameters
|
// Check we can open a device with standard parameters
|
||||||
|
/*
|
||||||
SDL_AudioSpec spec;
|
SDL_AudioSpec spec;
|
||||||
spec.freq = TargetSampleRate;
|
spec.freq = TargetSampleRate;
|
||||||
spec.channels = 2u;
|
spec.channels = 2u;
|
||||||
|
@ -256,6 +299,10 @@ bool IsSDLSuitable() {
|
||||||
|
|
||||||
SDL_AudioSpec obtained;
|
SDL_AudioSpec obtained;
|
||||||
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
|
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
|
||||||
|
*/
|
||||||
|
|
||||||
|
SDL_AudioSpec spec{.format = SDL_AUDIO_S16, .channels = 2, .freq = TargetSampleRate};
|
||||||
|
const auto device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
|
||||||
|
|
||||||
if (device == 0) {
|
if (device == 0) {
|
||||||
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
|
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
|
|
@ -13,8 +13,8 @@
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
#include "audio_core/sink/cubeb_sink.h"
|
#include "audio_core/sink/cubeb_sink.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include "audio_core/sink/sdl2_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#endif
|
#endif
|
||||||
#include "audio_core/sink/null_sink.h"
|
#include "audio_core/sink/null_sink.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -59,9 +59,9 @@ constexpr SinkDetails sink_details[] = {
|
||||||
&IsCubebSuitable,
|
&IsCubebSuitable,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
Settings::AudioEngine::Sdl2,
|
Settings::AudioEngine::Sdl3,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
return std::make_unique<SDLSink>(device_id);
|
return std::make_unique<SDLSink>(device_id);
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct EnumMetadata {
|
||||||
enum class AudioEngine : u32 {
|
enum class AudioEngine : u32 {
|
||||||
Auto,
|
Auto,
|
||||||
Cubeb,
|
Cubeb,
|
||||||
Sdl2,
|
Sdl3,
|
||||||
Null,
|
Null,
|
||||||
Oboe,
|
Oboe,
|
||||||
};
|
};
|
||||||
|
@ -89,7 +89,7 @@ template <>
|
||||||
inline std::vector<std::pair<std::string, AudioEngine>>
|
inline std::vector<std::pair<std::string, AudioEngine>>
|
||||||
EnumMetadata<AudioEngine>::Canonicalizations() {
|
EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||||
return {
|
return {
|
||||||
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
|
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl3", AudioEngine::Sdl3},
|
||||||
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ void Config::Initialize(const std::string& config_name) {
|
||||||
|
|
||||||
void Config::Initialize(const std::optional<std::string> config_path) {
|
void Config::Initialize(const std::optional<std::string> config_path) {
|
||||||
const std::filesystem::path default_sdl_config_path =
|
const std::filesystem::path default_sdl_config_path =
|
||||||
FS::GetSudachiPath(FS::SudachiPath::ConfigDir) / "sdl2-config.ini";
|
FS::GetSudachiPath(FS::SudachiPath::ConfigDir) / "sdl3-config.ini";
|
||||||
config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
|
config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
|
||||||
void(FS::CreateParentDir(config_loc));
|
void(FS::CreateParentDir(config_loc));
|
||||||
SetUpIni();
|
SetUpIni();
|
||||||
|
|
|
@ -47,7 +47,7 @@ else()
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_sources(input_common PRIVATE
|
target_sources(input_common PRIVATE
|
||||||
drivers/joycon.cpp
|
drivers/joycon.cpp
|
||||||
drivers/joycon.h
|
drivers/joycon.h
|
||||||
|
@ -73,8 +73,8 @@ if (ENABLE_SDL2)
|
||||||
helpers/joycon_protocol/rumble.cpp
|
helpers/joycon_protocol/rumble.cpp
|
||||||
helpers/joycon_protocol/rumble.h
|
helpers/joycon_protocol/rumble.h
|
||||||
)
|
)
|
||||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
target_link_libraries(input_common PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
target_compile_definitions(input_common PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LIBUSB)
|
if (ENABLE_LIBUSB)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,18 +15,14 @@
|
||||||
#include "input_common/input_engine.h"
|
#include "input_common/input_engine.h"
|
||||||
|
|
||||||
union SDL_Event;
|
union SDL_Event;
|
||||||
using SDL_GameController = struct _SDL_GameController;
|
|
||||||
using SDL_Joystick = struct _SDL_Joystick;
|
|
||||||
using SDL_JoystickID = s32;
|
|
||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
|
|
||||||
class SDLJoystick;
|
class SDLJoystick;
|
||||||
|
class SDLGamepad;
|
||||||
|
|
||||||
using ButtonBindings =
|
using ButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadButton>, 20>;
|
||||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
|
using ZButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadAxis>, 2>;
|
||||||
using ZButtonBindings =
|
|
||||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
|
||||||
|
|
||||||
class SDLDriver : public InputEngine {
|
class SDLDriver : public InputEngine {
|
||||||
public:
|
public:
|
||||||
|
@ -38,11 +34,13 @@ public:
|
||||||
|
|
||||||
void PumpEvents() const;
|
void PumpEvents() const;
|
||||||
|
|
||||||
/// Handle SDL_Events for joysticks from SDL_PollEvent
|
/// Handle SDL_Events for gamepads from SDL_PollEvent
|
||||||
void HandleGameControllerEvent(const SDL_Event& event);
|
void HandleGameControllerEvent(const SDL_Event& event);
|
||||||
|
void HandleGamepadEvent(const SDL_Event& event);
|
||||||
|
|
||||||
/// Get the nth joystick with the corresponding GUID
|
/// Get the nth joystick with the corresponding GUID
|
||||||
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
|
||||||
|
std::shared_ptr<SDLGamepad> GetSDLGamepadBySDLID(SDL_JoystickID sdl_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
|
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
|
||||||
|
@ -50,6 +48,8 @@ public:
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const Common::UUID& guid, int port);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const Common::UUID& guid, int port);
|
||||||
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
|
||||||
|
std::shared_ptr<SDLGamepad> GetSDLGamepadByGUID(const Common::UUID& guid, int port);
|
||||||
|
std::shared_ptr<SDLGamepad> GetSDLGamepadByGUID(const std::string& guid, int port);
|
||||||
|
|
||||||
std::vector<Common::ParamPackage> GetInputDevices() const override;
|
std::vector<Common::ParamPackage> GetInputDevices() const override;
|
||||||
|
|
||||||
|
@ -71,9 +71,12 @@ public:
|
||||||
private:
|
private:
|
||||||
void InitJoystick(int joystick_index);
|
void InitJoystick(int joystick_index);
|
||||||
void CloseJoystick(SDL_Joystick* sdl_joystick);
|
void CloseJoystick(SDL_Joystick* sdl_joystick);
|
||||||
|
void InitGamepad(int gamepad_index);
|
||||||
|
void CloseGamepad(SDL_Gamepad* sdl_gamepad);
|
||||||
|
|
||||||
/// Needs to be called before SDL_QuitSubSystem.
|
/// Needs to be called before SDL_QuitSubSystem.
|
||||||
void CloseJoysticks();
|
void CloseJoysticks();
|
||||||
|
void CloseGamepads();
|
||||||
|
|
||||||
/// Takes all vibrations from the queue and sends the command to the controller
|
/// Takes all vibrations from the queue and sends the command to the controller
|
||||||
void SendVibrations();
|
void SendVibrations();
|
||||||
|
@ -88,8 +91,8 @@ private:
|
||||||
|
|
||||||
Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
|
Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
|
||||||
|
|
||||||
Common::ParamPackage BuildParamPackageForBinding(
|
Common::ParamPackage BuildParamPackageForBinding(int port, const Common::UUID& guid,
|
||||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const;
|
const SDL_GamepadBinding& binding) const;
|
||||||
|
|
||||||
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
||||||
int axis_y, float offset_x,
|
int axis_y, float offset_x,
|
||||||
|
@ -97,17 +100,25 @@ private:
|
||||||
|
|
||||||
/// Returns the default button bindings list
|
/// Returns the default button bindings list
|
||||||
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
||||||
|
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLGamepad>& gamepad) const;
|
||||||
|
|
||||||
/// Returns the button mappings from a single controller
|
/// Returns the button mappings from a single controller
|
||||||
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||||
const ButtonBindings& switch_to_sdl_button,
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLGamepad>& gamepad,
|
||||||
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
|
||||||
/// Returns the button mappings from two different controllers
|
/// Returns the button mappings from two different controllers
|
||||||
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||||
const std::shared_ptr<SDLJoystick>& joystick2,
|
const std::shared_ptr<SDLJoystick>& joystick2,
|
||||||
const ButtonBindings& switch_to_sdl_button,
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLGamepad>& gamepad,
|
||||||
|
const std::shared_ptr<SDLGamepad>& gamepad2,
|
||||||
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
|
||||||
/// Returns true if the button is on the left joycon
|
/// Returns true if the button is on the left joycon
|
||||||
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
||||||
|
@ -118,6 +129,8 @@ private:
|
||||||
/// Map of GUID of a list of corresponding virtual Joysticks
|
/// Map of GUID of a list of corresponding virtual Joysticks
|
||||||
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
|
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
|
||||||
std::mutex joystick_map_mutex;
|
std::mutex joystick_map_mutex;
|
||||||
|
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLGamepad>>> gamepad_map;
|
||||||
|
std::mutex gamepad_map_mutex;
|
||||||
|
|
||||||
bool start_thread = false;
|
bool start_thread = false;
|
||||||
std::atomic<bool> initialized = false;
|
std::atomic<bool> initialized = false;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#ifdef HAVE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
#include "input_common/drivers/gc_adapter.h"
|
#include "input_common/drivers/gc_adapter.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include "input_common/drivers/joycon.h"
|
#include "input_common/drivers/joycon.h"
|
||||||
#include "input_common/drivers/sdl_driver.h"
|
#include "input_common/drivers/sdl_driver.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,7 +87,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
||||||
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
RegisterEngine("sdl", sdl);
|
RegisterEngine("sdl", sdl);
|
||||||
RegisterEngine("joycon", joycon);
|
RegisterEngine("joycon", joycon);
|
||||||
#endif
|
#endif
|
||||||
|
@ -121,7 +121,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
UnregisterEngine(virtual_amiibo);
|
UnregisterEngine(virtual_amiibo);
|
||||||
UnregisterEngine(virtual_gamepad);
|
UnregisterEngine(virtual_gamepad);
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
UnregisterEngine(sdl);
|
UnregisterEngine(sdl);
|
||||||
UnregisterEngine(joycon);
|
UnregisterEngine(joycon);
|
||||||
#endif
|
#endif
|
||||||
|
@ -151,7 +151,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
auto udp_devices = udp_client->GetInputDevices();
|
auto udp_devices = udp_client->GetInputDevices();
|
||||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
auto joycon_devices = joycon->GetInputDevices();
|
auto joycon_devices = joycon->GetInputDevices();
|
||||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||||
auto sdl_devices = sdl->GetInputDevices();
|
auto sdl_devices = sdl->GetInputDevices();
|
||||||
|
@ -186,7 +186,7 @@ struct InputSubsystem::Impl {
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return udp_client;
|
return udp_client;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return sdl;
|
return sdl;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ struct InputSubsystem::Impl {
|
||||||
if (engine == virtual_gamepad->GetEngineName()) {
|
if (engine == virtual_gamepad->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ struct InputSubsystem::Impl {
|
||||||
gcadapter->BeginConfiguration();
|
gcadapter->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->BeginConfiguration();
|
udp_client->BeginConfiguration();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->BeginConfiguration();
|
sdl->BeginConfiguration();
|
||||||
joycon->BeginConfiguration();
|
joycon->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
@ -314,7 +314,7 @@ struct InputSubsystem::Impl {
|
||||||
gcadapter->EndConfiguration();
|
gcadapter->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->EndConfiguration();
|
udp_client->EndConfiguration();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->EndConfiguration();
|
sdl->EndConfiguration();
|
||||||
joycon->EndConfiguration();
|
joycon->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
@ -322,7 +322,7 @@ struct InputSubsystem::Impl {
|
||||||
|
|
||||||
void PumpEvents() const {
|
void PumpEvents() const {
|
||||||
update_engine->PumpEvents();
|
update_engine->PumpEvents();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->PumpEvents();
|
sdl->PumpEvents();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ struct InputSubsystem::Impl {
|
||||||
std::shared_ptr<GCAdapter> gcadapter;
|
std::shared_ptr<GCAdapter> gcadapter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
std::shared_ptr<SDLDriver> sdl;
|
std::shared_ptr<SDLDriver> sdl;
|
||||||
std::shared_ptr<Joycons> joycon;
|
std::shared_ptr<Joycons> joycon;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -453,9 +453,9 @@ if (SUDACHI_USE_BUNDLED_QT AND QT_VERSION VERSION_LESS 6)
|
||||||
copy_sudachi_Qt5_deps(sudachi)
|
copy_sudachi_Qt5_deps(sudachi)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_link_libraries(sudachi PRIVATE SDL2::SDL2)
|
target_link_libraries(sudachi PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(sudachi PRIVATE HAVE_SDL2)
|
target_compile_definitions(sudachi PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
|
@ -87,7 +87,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include <SDL.h> // For SDL ScreenSaver functions
|
#include <SDL.h> // For SDL ScreenSaver functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -468,7 +468,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
|
||||||
VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
|
VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_SDL2) && !defined(_WIN32)
|
#if defined(HAVE_SDL3) && !defined(_WIN32)
|
||||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
// Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to
|
// Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to
|
||||||
|
@ -1760,7 +1760,7 @@ void GMainWindow::OnSigInterruptNotifierActivated() {
|
||||||
void GMainWindow::PreventOSSleep() {
|
void GMainWindow::PreventOSSleep() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
|
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
|
||||||
#elif defined(HAVE_SDL2)
|
#elif defined(HAVE_SDL3)
|
||||||
SDL_DisableScreenSaver();
|
SDL_DisableScreenSaver();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1768,7 +1768,7 @@ void GMainWindow::PreventOSSleep() {
|
||||||
void GMainWindow::AllowOSSleep() {
|
void GMainWindow::AllowOSSleep() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetThreadExecutionState(ES_CONTINUOUS);
|
SetThreadExecutionState(ES_CONTINUOUS);
|
||||||
#elif defined(HAVE_SDL2)
|
#elif defined(HAVE_SDL3)
|
||||||
SDL_EnableScreenSaver();
|
SDL_EnableScreenSaver();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,14 @@ function(create_resource file output filename)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_executable(sudachi-cmd
|
add_executable(sudachi-cmd
|
||||||
emu_window/emu_window_sdl2.cpp
|
emu_window/emu_window_sdl3.cpp
|
||||||
emu_window/emu_window_sdl2.h
|
emu_window/emu_window_sdl3.h
|
||||||
emu_window/emu_window_sdl2_gl.cpp
|
emu_window/emu_window_sdl3_gl.cpp
|
||||||
emu_window/emu_window_sdl2_gl.h
|
emu_window/emu_window_sdl3_gl.h
|
||||||
emu_window/emu_window_sdl2_null.cpp
|
emu_window/emu_window_sdl3_null.cpp
|
||||||
emu_window/emu_window_sdl2_null.h
|
emu_window/emu_window_sdl3_null.h
|
||||||
emu_window/emu_window_sdl2_vk.cpp
|
emu_window/emu_window_sdl3_vk.cpp
|
||||||
emu_window/emu_window_sdl2_vk.h
|
emu_window/emu_window_sdl3_vk.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
sdl_config.cpp
|
sdl_config.cpp
|
||||||
sdl_config.h
|
sdl_config.h
|
||||||
|
@ -38,7 +38,7 @@ target_link_libraries(sudachi-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads
|
||||||
create_resource("../../dist/sudachi.bmp" "sudachi_cmd/sudachi_icon.h" "sudachi_icon")
|
create_resource("../../dist/sudachi.bmp" "sudachi_cmd/sudachi_icon.h" "sudachi_icon")
|
||||||
target_include_directories(sudachi-cmd PRIVATE ${RESOURCES_DIR})
|
target_include_directories(sudachi-cmd PRIVATE ${RESOURCES_DIR})
|
||||||
|
|
||||||
target_link_libraries(sudachi-cmd PRIVATE SDL2::SDL2 Vulkan::Headers)
|
target_link_libraries(sudachi-cmd PRIVATE SDL3::SDL3 Vulkan::Headers)
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
install(TARGETS sudachi-cmd)
|
install(TARGETS sudachi-cmd)
|
||||||
|
|
|
@ -19,27 +19,27 @@
|
||||||
namespace FS = Common::FS;
|
namespace FS = Common::FS;
|
||||||
|
|
||||||
const std::filesystem::path default_config_path =
|
const std::filesystem::path default_config_path =
|
||||||
FS::GetSudachiPath(FS::SudachiPath::ConfigDir) / "sdl2-config.ini";
|
FS::GetSudachiPath(FS::SudachiPath::ConfigDir) / "sdl3-config.ini";
|
||||||
|
|
||||||
Config::Config(std::optional<std::filesystem::path> config_path)
|
Config::Config(std::optional<std::filesystem::path> config_path)
|
||||||
: sdl2_config_loc{config_path.value_or(default_config_path)},
|
: sdl3_config_loc{config_path.value_or(default_config_path)},
|
||||||
sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} {
|
sdl3_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl3_config_loc))} {
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::~Config() = default;
|
Config::~Config() = default;
|
||||||
|
|
||||||
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
||||||
const auto config_loc_str = FS::PathToUTF8String(sdl2_config_loc);
|
const auto config_loc_str = FS::PathToUTF8String(sdl3_config_loc);
|
||||||
if (sdl2_config->ParseError() < 0) {
|
if (sdl3_config->ParseError() < 0) {
|
||||||
if (retry) {
|
if (retry) {
|
||||||
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
|
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
|
||||||
config_loc_str);
|
config_loc_str);
|
||||||
|
|
||||||
void(FS::CreateParentDir(sdl2_config_loc));
|
void(FS::CreateParentDir(sdl3_config_loc));
|
||||||
void(FS::WriteStringToFile(sdl2_config_loc, FS::FileType::TextFile, default_contents));
|
void(FS::WriteStringToFile(sdl3_config_loc, FS::FileType::TextFile, default_contents));
|
||||||
|
|
||||||
sdl2_config = std::make_unique<INIReader>(config_loc_str);
|
sdl3_config = std::make_unique<INIReader>(config_loc_str);
|
||||||
|
|
||||||
return LoadINI(default_contents, false);
|
return LoadINI(default_contents, false);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
||||||
std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
std::string setting_value = sdl3_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||||
if (setting_value.empty()) {
|
if (setting_value.empty()) {
|
||||||
setting_value = setting.GetDefault();
|
setting_value = setting.GetDefault();
|
||||||
}
|
}
|
||||||
|
@ -89,12 +89,12 @@ void Config::ReadSetting(const std::string& group, Settings::Setting<std::string
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
||||||
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
setting = sdl3_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, bool ranged>
|
template <typename Type, bool ranged>
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
||||||
setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
|
setting = static_cast<Type>(sdl3_config->GetInteger(group, setting.GetLabel(),
|
||||||
static_cast<long>(setting.GetDefault())));
|
static_cast<long>(setting.GetDefault())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ void Config::ReadCategory(Settings::Category category) {
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
std::string setting_value =
|
std::string setting_value =
|
||||||
sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString());
|
sdl3_config->Get(category_name, setting->GetLabel(), setting->DefaultToString());
|
||||||
setting->LoadString(setting_value);
|
setting->LoadString(setting_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ void Config::ReadValues() {
|
||||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
player.buttons[i] =
|
player.buttons[i] =
|
||||||
sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
|
sdl3_config->Get(group, Settings::NativeButton::mapping[i], default_param);
|
||||||
if (player.buttons[i].empty()) {
|
if (player.buttons[i].empty()) {
|
||||||
player.buttons[i] = default_param;
|
player.buttons[i] = default_param;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ void Config::ReadValues() {
|
||||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
||||||
player.analogs[i] =
|
player.analogs[i] =
|
||||||
sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
|
sdl3_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
|
||||||
if (player.analogs[i].empty()) {
|
if (player.analogs[i].empty()) {
|
||||||
player.analogs[i] = default_param;
|
player.analogs[i] = default_param;
|
||||||
}
|
}
|
||||||
|
@ -148,18 +148,18 @@ void Config::ReadValues() {
|
||||||
auto& player_motions = player.motions[i];
|
auto& player_motions = player.motions[i];
|
||||||
|
|
||||||
player_motions =
|
player_motions =
|
||||||
sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param);
|
sdl3_config->Get(group, Settings::NativeMotion::mapping[i], default_param);
|
||||||
if (player_motions.empty()) {
|
if (player_motions.empty()) {
|
||||||
player_motions = default_param;
|
player_motions = default_param;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.connected = sdl2_config->GetBoolean(group, "connected", false);
|
player.connected = sdl3_config->GetBoolean(group, "connected", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
|
Settings::values.debug_pad_buttons[i] = sdl3_config->Get(
|
||||||
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i],
|
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i],
|
||||||
default_param);
|
default_param);
|
||||||
if (Settings::values.debug_pad_buttons[i].empty())
|
if (Settings::values.debug_pad_buttons[i].empty())
|
||||||
|
@ -170,7 +170,7 @@ void Config::ReadValues() {
|
||||||
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||||
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
||||||
Settings::values.debug_pad_analogs[i] = sdl2_config->Get(
|
Settings::values.debug_pad_analogs[i] = sdl3_config->Get(
|
||||||
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i],
|
"ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i],
|
||||||
default_param);
|
default_param);
|
||||||
if (Settings::values.debug_pad_analogs[i].empty())
|
if (Settings::values.debug_pad_analogs[i].empty())
|
||||||
|
@ -178,24 +178,24 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.touchscreen.enabled =
|
Settings::values.touchscreen.enabled =
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
sdl3_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
||||||
Settings::values.touchscreen.rotation_angle =
|
Settings::values.touchscreen.rotation_angle =
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0);
|
sdl3_config->GetInteger("ControlsGeneral", "touch_angle", 0);
|
||||||
Settings::values.touchscreen.diameter_x =
|
Settings::values.touchscreen.diameter_x =
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
|
sdl3_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
|
||||||
Settings::values.touchscreen.diameter_y =
|
Settings::values.touchscreen.diameter_y =
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
|
sdl3_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
|
||||||
|
|
||||||
int num_touch_from_button_maps =
|
int num_touch_from_button_maps =
|
||||||
sdl2_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
|
sdl3_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
|
||||||
if (num_touch_from_button_maps > 0) {
|
if (num_touch_from_button_maps > 0) {
|
||||||
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
||||||
Settings::TouchFromButtonMap map;
|
Settings::TouchFromButtonMap map;
|
||||||
map.name = sdl2_config->Get("ControlsGeneral",
|
map.name = sdl3_config->Get("ControlsGeneral",
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
std::string("touch_from_button_maps_") + std::to_string(i) +
|
||||||
std::string("_name"),
|
std::string("_name"),
|
||||||
"default");
|
"default");
|
||||||
const int num_touch_maps = sdl2_config->GetInteger(
|
const int num_touch_maps = sdl3_config->GetInteger(
|
||||||
"ControlsGeneral",
|
"ControlsGeneral",
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
|
std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
|
||||||
0);
|
0);
|
||||||
|
@ -203,7 +203,7 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
for (int j = 0; j < num_touch_maps; ++j) {
|
for (int j = 0; j < num_touch_maps; ++j) {
|
||||||
std::string touch_mapping =
|
std::string touch_mapping =
|
||||||
sdl2_config->Get("ControlsGeneral",
|
sdl3_config->Get("ControlsGeneral",
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
std::string("touch_from_button_maps_") + std::to_string(i) +
|
||||||
std::string("_bind_") + std::to_string(j),
|
std::string("_bind_") + std::to_string(j),
|
||||||
"");
|
"");
|
||||||
|
@ -239,28 +239,28 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
// Data Storage
|
// Data Storage
|
||||||
FS::SetSudachiPath(FS::SudachiPath::NANDDir,
|
FS::SetSudachiPath(FS::SudachiPath::NANDDir,
|
||||||
sdl2_config->Get("Data Storage", "nand_directory",
|
sdl3_config->Get("Data Storage", "nand_directory",
|
||||||
FS::GetSudachiPathString(FS::SudachiPath::NANDDir)));
|
FS::GetSudachiPathString(FS::SudachiPath::NANDDir)));
|
||||||
FS::SetSudachiPath(FS::SudachiPath::SDMCDir,
|
FS::SetSudachiPath(FS::SudachiPath::SDMCDir,
|
||||||
sdl2_config->Get("Data Storage", "sdmc_directory",
|
sdl3_config->Get("Data Storage", "sdmc_directory",
|
||||||
FS::GetSudachiPathString(FS::SudachiPath::SDMCDir)));
|
FS::GetSudachiPathString(FS::SudachiPath::SDMCDir)));
|
||||||
FS::SetSudachiPath(FS::SudachiPath::LoadDir,
|
FS::SetSudachiPath(FS::SudachiPath::LoadDir,
|
||||||
sdl2_config->Get("Data Storage", "load_directory",
|
sdl3_config->Get("Data Storage", "load_directory",
|
||||||
FS::GetSudachiPathString(FS::SudachiPath::LoadDir)));
|
FS::GetSudachiPathString(FS::SudachiPath::LoadDir)));
|
||||||
FS::SetSudachiPath(FS::SudachiPath::DumpDir,
|
FS::SetSudachiPath(FS::SudachiPath::DumpDir,
|
||||||
sdl2_config->Get("Data Storage", "dump_directory",
|
sdl3_config->Get("Data Storage", "dump_directory",
|
||||||
FS::GetSudachiPathString(FS::SudachiPath::DumpDir)));
|
FS::GetSudachiPathString(FS::SudachiPath::DumpDir)));
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
Settings::values.record_frame_times =
|
Settings::values.record_frame_times =
|
||||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
sdl3_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||||
|
|
||||||
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
|
const auto title_list = sdl3_config->Get("AddOns", "title_ids", "");
|
||||||
std::stringstream ss(title_list);
|
std::stringstream ss(title_list);
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(ss, line, '|')) {
|
while (std::getline(ss, line, '|')) {
|
||||||
const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
|
const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
|
||||||
const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, "");
|
const auto disabled_list = sdl3_config->Get("AddOns", "disabled_" + line, "");
|
||||||
|
|
||||||
std::stringstream inner_ss(disabled_list);
|
std::stringstream inner_ss(disabled_list);
|
||||||
std::string inner_line;
|
std::string inner_line;
|
||||||
|
@ -274,6 +274,6 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::Reload() {
|
void Config::Reload() {
|
||||||
LoadINI(DefaultINI::sdl2_config_file);
|
LoadINI(DefaultINI::sdl3_config_file);
|
||||||
ReadValues();
|
ReadValues();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
class INIReader;
|
class INIReader;
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
std::filesystem::path sdl2_config_loc;
|
std::filesystem::path sdl3_config_loc;
|
||||||
std::unique_ptr<INIReader> sdl2_config;
|
std::unique_ptr<INIReader> sdl3_config;
|
||||||
|
|
||||||
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
||||||
void ReadValues();
|
void ReadValues();
|
||||||
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Applies a value read from the sdl2_config to a Setting.
|
* Applies a value read from the sdl3_config to a Setting.
|
||||||
*
|
*
|
||||||
* @param group The name of the INI group
|
* @param group The name of the INI group
|
||||||
* @param setting The sudachi setting to modify
|
* @param setting The sudachi setting to modify
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
namespace DefaultINI {
|
namespace DefaultINI {
|
||||||
|
|
||||||
const char* sdl2_config_file =
|
const char* sdl3_config_file =
|
||||||
R"(
|
R"(
|
||||||
[ControlsP0]
|
[ControlsP0]
|
||||||
# The input devices and parameters for each Switch native input
|
# The input devices and parameters for each Switch native input
|
||||||
|
@ -424,7 +424,7 @@ bg_green =
|
||||||
# Which audio output engine to use.
|
# Which audio output engine to use.
|
||||||
# auto (default): Auto-select
|
# auto (default): Auto-select
|
||||||
# cubeb: Cubeb audio engine (if available)
|
# cubeb: Cubeb audio engine (if available)
|
||||||
# sdl2: SDL2 audio engine (if available)
|
# sdl3: SDL3 audio engine (if available)
|
||||||
# null: No audio output
|
# null: No audio output
|
||||||
output_engine =
|
output_engine =
|
||||||
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 sudachi Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/scm_rev.h"
|
|
||||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_vk.h"
|
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <SDL_syswm.h>
|
|
||||||
|
|
||||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_,
|
|
||||||
Core::System& system_, bool fullscreen)
|
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
|
||||||
const std::string window_title = fmt::format("sudachi {} | {}-{} (Vulkan)", Common::g_build_name,
|
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
|
||||||
render_window =
|
|
||||||
SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
|
||||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
|
||||||
|
|
||||||
SDL_SysWMinfo wm;
|
|
||||||
SDL_VERSION(&wm.version);
|
|
||||||
if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetWindowIcon();
|
|
||||||
|
|
||||||
if (fullscreen) {
|
|
||||||
Fullscreen();
|
|
||||||
ShowCursor(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (wm.subsystem) {
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
|
||||||
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
|
||||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
|
||||||
window_info.type = Core::Frontend::WindowSystemType::X11;
|
|
||||||
window_info.display_connection = wm.info.x11.display;
|
|
||||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
|
||||||
window_info.type = Core::Frontend::WindowSystemType::Wayland;
|
|
||||||
window_info.display_connection = wm.info.wl.display;
|
|
||||||
window_info.render_surface = wm.info.wl.surface;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_COCOA
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
|
|
||||||
window_info.type = Core::Frontend::WindowSystemType::Cocoa;
|
|
||||||
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
|
||||||
window_info.type = Core::Frontend::WindowSystemType::Android;
|
|
||||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnResize();
|
|
||||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
|
||||||
SDL_PumpEvents();
|
|
||||||
LOG_INFO(Frontend, "sudachi Version: {} | {}-{} (Vulkan)", Common::g_build_name,
|
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default;
|
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
|
|
||||||
return std::make_unique<DummyContext>();
|
|
||||||
}
|
|
|
@ -1,7 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#define SDL_MAIN_HANDLED
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <SDL_main.h>
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
|
@ -13,26 +15,27 @@
|
||||||
#include "input_common/drivers/mouse.h"
|
#include "input_common/drivers/mouse.h"
|
||||||
#include "input_common/drivers/touch_screen.h"
|
#include "input_common/drivers/touch_screen.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2.h"
|
#include "sudachi_cmd/emu_window/emu_window_sdl3.h"
|
||||||
#include "sudachi_cmd/sudachi_icon.h"
|
#include "sudachi_cmd/sudachi_icon.h"
|
||||||
|
|
||||||
EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
|
EmuWindow_SDL3::EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
|
||||||
: input_subsystem{input_subsystem_}, system{system_} {
|
: input_subsystem{input_subsystem_}, system{system_} {
|
||||||
input_subsystem->Initialize();
|
input_subsystem->Initialize();
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD) < 0) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetMainReady();
|
SDL_SetMainReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2::~EmuWindow_SDL2() {
|
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
||||||
system.HIDCore().UnloadInputDevices();
|
system.HIDCore().UnloadInputDevices();
|
||||||
input_subsystem->Shutdown();
|
input_subsystem->Shutdown();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
|
InputCommon::MouseButton EmuWindow_SDL3::SDLButtonToMouseButton(u32 button) const {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case SDL_BUTTON_LEFT:
|
case SDL_BUTTON_LEFT:
|
||||||
return InputCommon::MouseButton::Left;
|
return InputCommon::MouseButton::Left;
|
||||||
|
@ -49,7 +52,7 @@ InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<float, float> EmuWindow_SDL2::MouseToTouchPos(s32 touch_x, s32 touch_y) const {
|
std::pair<float, float> EmuWindow_SDL3::MouseToTouchPos(s32 touch_x, s32 touch_y) const {
|
||||||
int w, h;
|
int w, h;
|
||||||
SDL_GetWindowSize(render_window, &w, &h);
|
SDL_GetWindowSize(render_window, &w, &h);
|
||||||
const float fx = static_cast<float>(touch_x) / w;
|
const float fx = static_cast<float>(touch_x) / w;
|
||||||
|
@ -58,7 +61,7 @@ std::pair<float, float> EmuWindow_SDL2::MouseToTouchPos(s32 touch_x, s32 touch_y
|
||||||
return {std::clamp<float>(fx, 0.0f, 1.0f), std::clamp<float>(fy, 0.0f, 1.0f)};
|
return {std::clamp<float>(fx, 0.0f, 1.0f), std::clamp<float>(fy, 0.0f, 1.0f)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
void EmuWindow_SDL3::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
||||||
const auto mouse_button = SDLButtonToMouseButton(button);
|
const auto mouse_button = SDLButtonToMouseButton(button);
|
||||||
if (state == SDL_PRESSED) {
|
if (state == SDL_PRESSED) {
|
||||||
const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
|
const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
|
||||||
|
@ -70,26 +73,26 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
|
void EmuWindow_SDL3::OnMouseMotion(s32 x, s32 y) {
|
||||||
const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
|
const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
|
||||||
input_subsystem->GetMouse()->Move(x, y, 0, 0);
|
input_subsystem->GetMouse()->Move(x, y, 0, 0);
|
||||||
input_subsystem->GetMouse()->MouseMove(touch_x, touch_y);
|
input_subsystem->GetMouse()->MouseMove(touch_x, touch_y);
|
||||||
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
|
void EmuWindow_SDL3::OnFingerDown(float x, float y, std::size_t id) {
|
||||||
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
|
void EmuWindow_SDL3::OnFingerMotion(float x, float y, std::size_t id) {
|
||||||
input_subsystem->GetTouchScreen()->TouchMoved(x, y, id);
|
input_subsystem->GetTouchScreen()->TouchMoved(x, y, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerUp() {
|
void EmuWindow_SDL3::OnFingerUp() {
|
||||||
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
|
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
|
void EmuWindow_SDL3::OnKeyEvent(int key, u8 state) {
|
||||||
if (state == SDL_PRESSED) {
|
if (state == SDL_PRESSED) {
|
||||||
input_subsystem->GetKeyboard()->PressKey(static_cast<std::size_t>(key));
|
input_subsystem->GetKeyboard()->PressKey(static_cast<std::size_t>(key));
|
||||||
} else if (state == SDL_RELEASED) {
|
} else if (state == SDL_RELEASED) {
|
||||||
|
@ -97,32 +100,33 @@ void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_SDL2::IsOpen() const {
|
bool EmuWindow_SDL3::IsOpen() const {
|
||||||
return is_open;
|
return is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_SDL2::IsShown() const {
|
bool EmuWindow_SDL3::IsShown() const {
|
||||||
return is_shown;
|
return is_shown;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnResize() {
|
void EmuWindow_SDL3::OnResize() {
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GL_GetDrawableSize(render_window, &width, &height);
|
SDL_GetWindowSizeInPixels(render_window, &width, &height);
|
||||||
UpdateCurrentFramebufferLayout(width, height);
|
UpdateCurrentFramebufferLayout(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::ShowCursor(bool show_cursor) {
|
void EmuWindow_SDL3::ShowCursor(bool show_cursor) {
|
||||||
SDL_ShowCursor(show_cursor ? SDL_ENABLE : SDL_DISABLE);
|
show_cursor ? SDL_ShowCursor() : SDL_HideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::Fullscreen() {
|
void EmuWindow_SDL3::Fullscreen() {
|
||||||
SDL_DisplayMode display_mode;
|
const SDL_DisplayMode* display_mode = nullptr;
|
||||||
switch (Settings::values.fullscreen_mode.GetValue()) {
|
switch (Settings::values.fullscreen_mode.GetValue()) {
|
||||||
case Settings::FullscreenMode::Exclusive:
|
case Settings::FullscreenMode::Exclusive:
|
||||||
// Set window size to render size before entering fullscreen -- SDL2 does not resize window
|
// Set window size to render size before entering fullscreen -- SDL3 does not resize window
|
||||||
// to display dimensions automatically in this mode.
|
// to display dimensions automatically in this mode.
|
||||||
if (SDL_GetDesktopDisplayMode(0, &display_mode) == 0) {
|
display_mode = SDL_GetDesktopDisplayMode(0);
|
||||||
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
if (display_mode == NULL) {
|
||||||
|
SDL_SetWindowSize(render_window, display_mode->w, display_mode->h);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Frontend, "SDL_GetDesktopDisplayMode failed: {}", SDL_GetError());
|
LOG_ERROR(Frontend, "SDL_GetDesktopDisplayMode failed: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
@ -135,7 +139,7 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||||
LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
|
LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case Settings::FullscreenMode::Borderless:
|
case Settings::FullscreenMode::Borderless:
|
||||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
|
if (SDL_SetWindowFullscreen(render_window, SDL_TRUE) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +154,7 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::WaitEvent() {
|
void EmuWindow_SDL3::WaitEvent() {
|
||||||
// Called on main thread
|
// Called on main thread
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
|
||||||
|
@ -168,59 +172,55 @@ void EmuWindow_SDL2::WaitEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
switch (event.window.event) {
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
|
||||||
case SDL_WINDOWEVENT_RESTORED:
|
|
||||||
OnResize();
|
OnResize();
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_MINIMIZED:
|
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||||
case SDL_WINDOWEVENT_EXPOSED:
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED;
|
is_shown = event.window.type == SDL_EVENT_WINDOW_EXPOSED;
|
||||||
OnResize();
|
OnResize();
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_CLOSE:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
break;
|
||||||
}
|
case SDL_EVENT_KEY_DOWN:
|
||||||
break;
|
case SDL_EVENT_KEY_UP:
|
||||||
case SDL_KEYDOWN:
|
|
||||||
case SDL_KEYUP:
|
|
||||||
OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
|
OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID)
|
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||||
OnMouseMotion(event.motion.x, event.motion.y);
|
OnMouseMotion(static_cast<s32>(event.motion.x), static_cast<s32>(event.motion.y));
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
||||||
OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y);
|
OnMouseButton(event.button.button, event.button.state, static_cast<s32>(event.button.x),
|
||||||
|
static_cast<s32>(event.button.y));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERDOWN:
|
case SDL_EVENT_FINGER_DOWN:
|
||||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
||||||
static_cast<std::size_t>(event.tfinger.touchId));
|
static_cast<std::size_t>(event.tfinger.touchID));
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERMOTION:
|
case SDL_EVENT_FINGER_MOTION:
|
||||||
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
||||||
static_cast<std::size_t>(event.tfinger.touchId));
|
static_cast<std::size_t>(event.tfinger.touchID));
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERUP:
|
case SDL_EVENT_FINGER_UP:
|
||||||
OnFingerUp();
|
OnFingerUp();
|
||||||
break;
|
break;
|
||||||
case SDL_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 current_time = SDL_GetTicks();
|
const u64 current_time = SDL_GetTicks();
|
||||||
if (current_time > last_time + 2000) {
|
if (current_time > last_time + 2000) {
|
||||||
const auto results = system.GetAndResetPerfStats();
|
const auto results = system.GetAndResetPerfStats();
|
||||||
const auto title =
|
const auto title =
|
||||||
|
@ -233,22 +233,23 @@ void EmuWindow_SDL2::WaitEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credits to Samantas5855 and others for this function.
|
// Credits to Samantas5855 and others for this function.
|
||||||
void EmuWindow_SDL2::SetWindowIcon() {
|
void EmuWindow_SDL3::SetWindowIcon() {
|
||||||
SDL_RWops* const sudachi_icon_stream = SDL_RWFromConstMem((void*)sudachi_icon, sudachi_icon_size);
|
SDL_IOStream* const sudachi_icon_stream =
|
||||||
|
SDL_IOFromConstMem((void*)sudachi_icon, sudachi_icon_size);
|
||||||
if (sudachi_icon_stream == nullptr) {
|
if (sudachi_icon_stream == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to create sudachi icon stream.");
|
LOG_WARNING(Frontend, "Failed to create sudachi icon stream.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_Surface* const window_icon = SDL_LoadBMP_RW(sudachi_icon_stream, 1);
|
SDL_Surface* const window_icon = SDL_LoadBMP_IO(sudachi_icon_stream, 1);
|
||||||
if (window_icon == nullptr) {
|
if (window_icon == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to read BMP from stream.");
|
LOG_WARNING(Frontend, "Failed to read BMP from stream.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The icon is attached to the window pointer
|
// The icon is attached to the window pointer
|
||||||
SDL_SetWindowIcon(render_window, window_icon);
|
SDL_SetWindowIcon(render_window, window_icon);
|
||||||
SDL_FreeSurface(window_icon);
|
SDL_DestroySurface(window_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||||
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
|
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
|
||||||
}
|
}
|
|
@ -19,10 +19,10 @@ class InputSubsystem;
|
||||||
enum class MouseButton;
|
enum class MouseButton;
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
||||||
|
|
||||||
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
class EmuWindow_SDL3 : public Core::Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_);
|
explicit EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_);
|
||||||
~EmuWindow_SDL2();
|
~EmuWindow_SDL3();
|
||||||
|
|
||||||
/// Whether the window is still open, and a close request hasn't yet been sent
|
/// Whether the window is still open, and a close request hasn't yet been sent
|
||||||
bool IsOpen() const;
|
bool IsOpen() const;
|
||||||
|
@ -79,11 +79,11 @@ protected:
|
||||||
/// Is the window being shown?
|
/// Is the window being shown?
|
||||||
bool is_shown = true;
|
bool is_shown = true;
|
||||||
|
|
||||||
/// Internal SDL2 render window
|
/// Internal SDL3 render window
|
||||||
SDL_Window* render_window{};
|
SDL_Window* render_window{};
|
||||||
|
|
||||||
/// Keeps track of how often to update the title bar during gameplay
|
/// Keeps track of how often to update the title bar during gameplay
|
||||||
u32 last_time = 0;
|
u64 last_time = 0;
|
||||||
|
|
||||||
/// Input subsystem to use with this window.
|
/// Input subsystem to use with this window.
|
||||||
InputCommon::InputSubsystem* input_subsystem;
|
InputCommon::InputSubsystem* input_subsystem;
|
|
@ -16,8 +16,8 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_gl.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_gl.h"
|
|
||||||
|
|
||||||
class SDLGLContext : public Core::Frontend::GraphicsContext {
|
class SDLGLContext : public Core::Frontend::GraphicsContext {
|
||||||
public:
|
public:
|
||||||
|
@ -55,7 +55,7 @@ private:
|
||||||
bool is_current = false;
|
bool is_current = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
|
bool EmuWindow_SDL3_GL::SupportsRequiredGLExtensions() {
|
||||||
std::vector<std::string_view> unsupported_ext;
|
std::vector<std::string_view> unsupported_ext;
|
||||||
|
|
||||||
// Extensions required to support some texture formats.
|
// Extensions required to support some texture formats.
|
||||||
|
@ -73,9 +73,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
|
||||||
return unsupported_ext.empty();
|
return unsupported_ext.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_,
|
EmuWindow_SDL3_GL::EmuWindow_SDL3_GL(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system_, bool fullscreen)
|
Core::System& system_, bool fullscreen)
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||||
|
@ -93,14 +93,11 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
std::string window_title = fmt::format("sudachi {} | {}-{}", Common::g_build_fullname,
|
std::string window_title = fmt::format("sudachi {} | {}-{}", Common::g_build_fullname,
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
render_window =
|
render_window =
|
||||||
SDL_CreateWindow(window_title.c_str(),
|
SDL_CreateWindow(window_title.c_str(), Layout::ScreenUndocked::Width,
|
||||||
SDL_WINDOWPOS_UNDEFINED, // x position
|
Layout::ScreenUndocked::Height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||||
SDL_WINDOWPOS_UNDEFINED, // y position
|
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
|
||||||
|
|
||||||
if (render_window == nullptr) {
|
if (render_window == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create SDL3 window! {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,15 +114,15 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
core_context = CreateSharedContext();
|
core_context = CreateSharedContext();
|
||||||
|
|
||||||
if (window_context == nullptr) {
|
if (window_context == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create SDL3 GL context: {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (core_context == nullptr) {
|
if (core_context == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create shared SDL3 GL context: {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -138,16 +135,16 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
OnResize();
|
OnResize();
|
||||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
LOG_INFO(Frontend, "sudachi Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
|
LOG_INFO(Frontend, "sudachi Version: {} | {}-{}", Common::g_build_fullname,
|
||||||
Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
Settings::LogSettings();
|
Settings::LogSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
|
EmuWindow_SDL3_GL::~EmuWindow_SDL3_GL() {
|
||||||
core_context.reset();
|
core_context.reset();
|
||||||
SDL_GL_DeleteContext(window_context);
|
SDL_GL_DeleteContext(window_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_GL::CreateSharedContext() const {
|
||||||
return std::make_unique<SDLGLContext>(render_window);
|
return std::make_unique<SDLGLContext>(render_window);
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2.h"
|
#include "sudachi_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -15,11 +15,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_GL final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_,
|
explicit EmuWindow_SDL3_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_,
|
||||||
bool fullscreen);
|
bool fullscreen);
|
||||||
~EmuWindow_SDL2_GL();
|
~EmuWindow_SDL3_GL();
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_null.h"
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_null.h"
|
||||||
#include "video_core/renderer_null/renderer_null.h"
|
#include "video_core/renderer_null/renderer_null.h"
|
||||||
|
|
||||||
#ifdef SUDACHI_USE_EXTERNAL_SDL2
|
#ifdef SUDACHI_USE_EXTERNAL_SDL3
|
||||||
// Include this before SDL.h to prevent the external from including a dummy
|
// Include this before SDL.h to prevent the external from including a dummy
|
||||||
#define USING_GENERATED_CONFIG_H
|
#define USING_GENERATED_CONFIG_H
|
||||||
#include <SDL_config.h>
|
#include <SDL_config.h>
|
||||||
|
@ -20,16 +20,14 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_,
|
EmuWindow_SDL3_Null::EmuWindow_SDL3_Null(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system_, bool fullscreen)
|
Core::System& system_, bool fullscreen)
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
const std::string window_title =
|
const std::string window_title =
|
||||||
fmt::format("sudachi {} | {}-{} (Vulkan)", Common::g_build_name, Common::g_scm_branch,
|
fmt::format("sudachi {} | {}-{} (Vulkan)", Common::g_build_name, Common::g_scm_branch,
|
||||||
Common::g_scm_desc);
|
Common::g_scm_desc);
|
||||||
render_window =
|
render_window = SDL_CreateWindow(window_title.c_str(), Layout::ScreenUndocked::Width,
|
||||||
SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
Layout::ScreenUndocked::Height, SDL_WINDOW_RESIZABLE);
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
|
||||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
|
||||||
|
|
||||||
SetWindowIcon();
|
SetWindowIcon();
|
||||||
|
|
||||||
|
@ -45,8 +43,8 @@ EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subs
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_Null::~EmuWindow_SDL2_Null() = default;
|
EmuWindow_SDL3_Null::~EmuWindow_SDL3_Null() = default;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Null::CreateSharedContext() const {
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_Null::CreateSharedContext() const {
|
||||||
return std::make_unique<DummyContext>();
|
return std::make_unique<DummyContext>();
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2.h"
|
#include "sudachi_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -16,11 +16,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_Null final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_Null final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_,
|
explicit EmuWindow_SDL3_Null(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system, bool fullscreen);
|
Core::System& system, bool fullscreen);
|
||||||
~EmuWindow_SDL2_Null() override;
|
~EmuWindow_SDL3_Null() override;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
};
|
};
|
|
@ -0,0 +1,100 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 sudachi Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scm_rev.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_vk.h"
|
||||||
|
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
EmuWindow_SDL3_VK::EmuWindow_SDL3_VK(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
|
Core::System& system_, bool fullscreen)
|
||||||
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
|
const std::string window_title =
|
||||||
|
fmt::format("sudachi {} | {}-{} (Vulkan)", Common::g_build_name, Common::g_scm_branch,
|
||||||
|
Common::g_scm_desc);
|
||||||
|
render_window = SDL_CreateWindow(window_title.c_str(), Layout::ScreenUndocked::Width,
|
||||||
|
Layout::ScreenUndocked::Height, SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
|
// SDL_SysWMinfo wm;
|
||||||
|
// SDL_VERSION(&wm.version);
|
||||||
|
// if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
|
||||||
|
// LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}",
|
||||||
|
// SDL_GetError());
|
||||||
|
// std::exit(EXIT_FAILURE);
|
||||||
|
// }
|
||||||
|
|
||||||
|
SetWindowIcon();
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
Fullscreen();
|
||||||
|
ShowCursor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(SDL_PLATFORM_WIN32)
|
||||||
|
HWND hwnd = (HWND)SDL_GetProperty(SDL_GetWindowProperties(render_window),
|
||||||
|
SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(hwnd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
switch (wm.subsystem) {
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_X11
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::X11;
|
||||||
|
window_info.display_connection = wm.info.x11.display;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Wayland;
|
||||||
|
window_info.display_connection = wm.info.wl.display;
|
||||||
|
window_info.render_surface = wm.info.wl.surface;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Cocoa;
|
||||||
|
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
OnResize();
|
||||||
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
|
SDL_PumpEvents();
|
||||||
|
LOG_INFO(Frontend, "sudachi Version: {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||||
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmuWindow_SDL3_VK::~EmuWindow_SDL3_VK() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_VK::CreateSharedContext() const {
|
||||||
|
return std::make_unique<DummyContext>();
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2.h"
|
#include "sudachi_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -16,11 +16,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_VK final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system,
|
explicit EmuWindow_SDL3_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system,
|
||||||
bool fullscreen);
|
bool fullscreen);
|
||||||
~EmuWindow_SDL2_VK() override;
|
~EmuWindow_SDL3_VK() override;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
};
|
};
|
|
@ -34,11 +34,11 @@
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "sdl_config.h"
|
#include "sdl_config.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_gl.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_null.h"
|
||||||
|
#include "sudachi_cmd/emu_window/emu_window_sdl3_vk.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2.h"
|
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_gl.h"
|
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_null.h"
|
|
||||||
#include "sudachi_cmd/emu_window/emu_window_sdl2_vk.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// windows.h needs to be included before shellapi.h
|
// windows.h needs to be included before shellapi.h
|
||||||
|
@ -346,16 +346,16 @@ int main(int argc, char** argv) {
|
||||||
// Apply the command line arguments
|
// Apply the command line arguments
|
||||||
system.ApplySettings();
|
system.ApplySettings();
|
||||||
|
|
||||||
std::unique_ptr<EmuWindow_SDL2> emu_window;
|
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
||||||
switch (Settings::values.renderer_backend.GetValue()) {
|
switch (Settings::values.renderer_backend.GetValue()) {
|
||||||
case Settings::RendererBackend::OpenGL:
|
case Settings::RendererBackend::OpenGL:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Vulkan:
|
case Settings::RendererBackend::Vulkan:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Null:
|
case Settings::RendererBackend::Null:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_Null>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,8 @@ int main(int argc, char** argv) {
|
||||||
static_cast<u32>(Core::SystemResultStatus::ErrorLoader)) {
|
static_cast<u32>(Core::SystemResultStatus::ErrorLoader)) {
|
||||||
const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
|
const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
|
||||||
const u16 error_id = static_cast<u16>(load_result) - loader_id;
|
const u16 error_id = static_cast<u16>(load_result) - loader_id;
|
||||||
LOG_CRITICAL(Frontend,
|
LOG_CRITICAL(
|
||||||
|
Frontend,
|
||||||
"While attempting to load the ROM requested, an error occurred. Please "
|
"While attempting to load the ROM requested, an error occurred. Please "
|
||||||
"refer to the sudachi wiki for more information or the sudachi discord for "
|
"refer to the sudachi wiki for more information or the sudachi discord for "
|
||||||
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
||||||
|
|
Loading…
Reference in New Issue