mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-16 05:21:22 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a897331edf | |||
| 6af5e176ed | |||
| 3eca67617a | |||
| e7a931d06b |
-1
@@ -30,7 +30,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||||
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||||
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
||||||
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
|
|
||||||
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
||||||
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
||||||
RENDERER_DEBUG("debug"),
|
RENDERER_DEBUG("debug"),
|
||||||
|
|||||||
-7
@@ -808,13 +808,6 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.enable_buffer_history_description
|
descriptionId = R.string.enable_buffer_history_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SwitchSetting(
|
|
||||||
BooleanSetting.ENABLE_GPU_BUFFER_READBACK,
|
|
||||||
titleId = R.string.enable_gpu_buffer_readback,
|
|
||||||
descriptionId = R.string.enable_gpu_buffer_readback_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
|
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
|
||||||
|
|||||||
-1
@@ -294,7 +294,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||||
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
||||||
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
|
|
||||||
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
|
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.hacks))
|
add(HeaderSetting(R.string.hacks))
|
||||||
|
|||||||
@@ -499,8 +499,6 @@
|
|||||||
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
|
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
|
||||||
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
||||||
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
||||||
<string name="enable_gpu_buffer_readback">تفعيل قراءة مخزن وحدة معالجة الرسومات</string>
|
|
||||||
<string name="enable_gpu_buffer_readback_description">يحافظ هذا النظام على بيانات المخزن المؤقت المُعدّلة بواسطة وحدة معالجة الرسومات عن طريق قراءتها مرة أخرى قبل التحميل. تتطلب بعض الألعاب ذلك لعرض بعض التأثيرات بشكل صحيح. قد يُسبب ذلك مشاكل إذا لم يتمكن الجهاز من التعامل مع عبء العمل الإضافي.</string>
|
|
||||||
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
|
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
|
||||||
|
|
||||||
|
|||||||
@@ -491,8 +491,6 @@
|
|||||||
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
|
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
|
||||||
<string name="enable_buffer_history">Activar el historial del búfer</string>
|
<string name="enable_buffer_history">Activar el historial del búfer</string>
|
||||||
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
|
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
|
||||||
<string name="enable_gpu_buffer_readback">Activar la lectura del buffer de la GPU</string>
|
|
||||||
<string name="enable_gpu_buffer_readback_description">Conserva los datos del búfer modificados por la GPU leyéndolos antes de subirlos.\nAlgunos juegos requieren esto para renderizar correctamente ciertos efectos.\nPuede causar problemas si el hardware no puede soportar la carga de trabajo adicional.</string>
|
|
||||||
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
|
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
|
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
|
||||||
|
|
||||||
|
|||||||
@@ -489,8 +489,6 @@
|
|||||||
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
|
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
|
||||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||||
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
|
|
||||||
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏会用到这项设定以正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
|
|
||||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
||||||
|
|
||||||
|
|||||||
@@ -505,8 +505,6 @@
|
|||||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||||
<string name="enable_buffer_history">Enable buffer history</string>
|
<string name="enable_buffer_history">Enable buffer history</string>
|
||||||
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
|
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
|
||||||
<string name="enable_gpu_buffer_readback">Enable GPU Buffer Readback</string>
|
|
||||||
<string name="enable_gpu_buffer_readback_description">Preserves GPU-modified buffer data by reading it back before uploads. Some games require this to render certain effects properly. May cause issues if the hardware cannot handle the additional workload.</string>
|
|
||||||
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
|
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
|
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
|
||||||
|
|
||||||
|
|||||||
@@ -576,13 +576,6 @@ struct Values {
|
|||||||
false,
|
false,
|
||||||
#endif
|
#endif
|
||||||
"rescale_hack", Category::RendererHacks};
|
"rescale_hack", Category::RendererHacks};
|
||||||
SwitchableSetting<bool> enable_gpu_buffer_readback{linkage,
|
|
||||||
false,
|
|
||||||
"enable_gpu_buffer_readback",
|
|
||||||
Category::RendererAdvanced,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
|
|
||||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||||
Category::RendererHacks};
|
Category::RendererHacks};
|
||||||
|
|||||||
@@ -223,8 +223,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."));
|
tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."));
|
||||||
INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"),
|
INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"),
|
||||||
tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nStrict is the slowest option, but can fix issues that require stricter synchronization.\nDefault follows the GPU Accuracy setting."));
|
tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nStrict is the slowest option, but can fix issues that require stricter synchronization.\nDefault follows the GPU Accuracy setting."));
|
||||||
INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"),
|
|
||||||
tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
|
|
||||||
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
||||||
tr("May reduce shader stutter."));
|
tr("May reduce shader stutter."));
|
||||||
INSERT(Settings, gpu_clock, tr("GPU Clocks"),
|
INSERT(Settings, gpu_clock, tr("GPU Clocks"),
|
||||||
|
|||||||
@@ -1448,8 +1448,8 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
|
|||||||
const BufferId buffer_id = page_table[page];
|
const BufferId buffer_id = page_table[page];
|
||||||
if (buffer_id) {
|
if (buffer_id) {
|
||||||
Buffer& buffer = slot_buffers[buffer_id];
|
Buffer& buffer = slot_buffers[buffer_id];
|
||||||
WaitForGpuFenceIfNeeded(buffer);
|
|
||||||
if (buffer.IsInBounds(device_addr, size)) {
|
if (buffer.IsInBounds(device_addr, size)) {
|
||||||
|
SynchronizeBufferIfNeeded(buffer);
|
||||||
return buffer_id;
|
return buffer_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1457,16 +1457,28 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::WaitForGpuFenceIfNeeded(Buffer& buffer) {
|
void BufferCache<P>::SynchronizeBufferIfNeeded(Buffer& buffer) {
|
||||||
if constexpr (!IS_OPENGL) {
|
const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
|
||||||
const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
|
const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
|
||||||
const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
|
const bool should_sync = gpu_fence_accurate || gpu_fence_strict;
|
||||||
if (gpu_fence_accurate || gpu_fence_strict) {
|
if (should_sync) {
|
||||||
const u64 gpu_tick_delay = gpu_fence_strict ? 0 : 3;
|
if (gpu_fence_accurate) {
|
||||||
const u64 buffer_tick = buffer.getWriteTick();
|
if constexpr (!IS_OPENGL) {
|
||||||
const u64 gpu_tick = runtime.KnownGpuTick();
|
const bool should_wait = buffer.getWriteTick() > runtime.KnownGpuTick() + 3;
|
||||||
if (buffer_tick > gpu_tick + gpu_tick_delay) {
|
if (should_wait) {
|
||||||
runtime.Wait(buffer_tick);
|
runtime.Wait(buffer.getWriteTick());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (gpu_fence_strict) {
|
||||||
|
bool should_download = true;
|
||||||
|
if constexpr (!IS_OPENGL) {
|
||||||
|
should_download = buffer.getWriteTick() > runtime.KnownGpuTick();
|
||||||
|
if (should_download) {
|
||||||
|
runtime.Wait(buffer.getWriteTick());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (should_download) {
|
||||||
|
DownloadBufferMemory(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1688,9 +1700,6 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
if (immediate_buffer.empty()) {
|
if (immediate_buffer.empty()) {
|
||||||
immediate_buffer = ImmediateBuffer(largest_copy);
|
immediate_buffer = ImmediateBuffer(largest_copy);
|
||||||
}
|
}
|
||||||
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
|
||||||
DownloadBufferMemory(buffer, device_addr, copy.size);
|
|
||||||
}
|
|
||||||
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
|
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
|
||||||
upload_span = immediate_buffer.subspan(0, copy.size);
|
upload_span = immediate_buffer.subspan(0, copy.size);
|
||||||
}
|
}
|
||||||
@@ -1709,9 +1718,6 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
for (BufferCopy& copy : copies) {
|
for (BufferCopy& copy : copies) {
|
||||||
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
||||||
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
||||||
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
|
||||||
DownloadBufferMemory(buffer, device_addr, copy.size);
|
|
||||||
}
|
|
||||||
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
||||||
// Apply the staging offset
|
// Apply the staging offset
|
||||||
copy.src_offset += upload_staging.offset;
|
copy.src_offset += upload_staging.offset;
|
||||||
|
|||||||
@@ -435,6 +435,8 @@ private:
|
|||||||
|
|
||||||
bool SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size);
|
bool SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size);
|
||||||
|
|
||||||
|
void SynchronizeBufferIfNeeded(Buffer& buffer);
|
||||||
|
|
||||||
void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
|
void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
|
||||||
std::span<BufferCopy> copies);
|
std::span<BufferCopy> copies);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
@@ -26,9 +30,17 @@ EmuWindow_SDL3::EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Co
|
|||||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
titlebar_timer = SDL_AddTimer(2000, [](void *userdata, SDL_TimerID, Uint32) -> Uint32 {
|
||||||
|
auto* this_ = (EmuWindow_SDL3*)userdata;
|
||||||
|
auto const results = this_->system.GetAndResetPerfStats();
|
||||||
|
auto const title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps, results.emulation_speed * 100.0f);
|
||||||
|
SDL_SetWindowTitle(this_->render_window, title.c_str());
|
||||||
|
return 2000;
|
||||||
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
||||||
|
SDL_RemoveTimer(titlebar_timer);
|
||||||
system.HIDCore().UnloadInputDevices();
|
system.HIDCore().UnloadInputDevices();
|
||||||
input_subsystem->Shutdown();
|
input_subsystem->Shutdown();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
@@ -132,8 +144,7 @@ void EmuWindow_SDL3::Fullscreen() {
|
|||||||
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 in exclusive mode.
|
// Set window size to render size before entering fullscreen in exclusive mode.
|
||||||
if (const SDL_DisplayMode* display_mode_ptr =
|
if (const SDL_DisplayMode* display_mode_ptr = SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
||||||
SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
|
||||||
display_mode = *display_mode_ptr;
|
display_mode = *display_mode_ptr;
|
||||||
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
||||||
SDL_SetWindowFullscreenMode(render_window, &display_mode);
|
SDL_SetWindowFullscreenMode(render_window, &display_mode);
|
||||||
@@ -165,92 +176,60 @@ void EmuWindow_SDL3::Fullscreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL3::WaitEvent() {
|
void EmuWindow_SDL3::OnEvent(SDL_Event& event) {
|
||||||
// Called on main thread
|
// Notice how we skip the "update title" aspect on most events
|
||||||
SDL_Event event;
|
// this is because some WMs do NOT like changing titles while resizing
|
||||||
|
// so let's just... not do that, thanks :)
|
||||||
if (!SDL_WaitEvent(&event)) {
|
// Afterall we don't really expect the user to pay attention to the titlebar
|
||||||
const char* error = SDL_GetError();
|
// while they're moving a lot of shit around...
|
||||||
if (!error || strcmp(error, "") == 0) {
|
|
||||||
// https://github.com/libsdl-org/SDL/issues/5780
|
|
||||||
// Sometimes SDL will return without actually having hit an error condition;
|
|
||||||
// just ignore it in this case.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_EVENT_WINDOW_RESIZED:
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||||
is_shown = false;
|
is_shown = false;
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_EXPOSED:
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
is_shown = true;
|
is_shown = true;
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
return;
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
OnKeyEvent(static_cast<int>(event.key.scancode), event.key.down ? 1 : 0);
|
return OnKeyEvent(int(event.key.scancode), event.key.down ? 1 : 0);
|
||||||
break;
|
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
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(event.motion.x, event.motion.y);
|
||||||
break;
|
return;
|
||||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
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.down ? 1 : 0,
|
OnMouseButton(event.button.button, event.button.down ? 1 : 0, s32(event.button.x), s32(event.button.y));
|
||||||
static_cast<s32>(event.button.x), static_cast<s32>(event.button.y));
|
return;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_DOWN:
|
case SDL_EVENT_FINGER_DOWN:
|
||||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
return OnFingerDown(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||||
static_cast<std::size_t>(event.tfinger.touchID));
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_MOTION:
|
case SDL_EVENT_FINGER_MOTION:
|
||||||
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
return OnFingerMotion(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||||
static_cast<std::size_t>(event.tfinger.touchID));
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_UP:
|
case SDL_EVENT_FINGER_UP:
|
||||||
OnFingerUp();
|
return OnFingerUp();
|
||||||
break;
|
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 current_time = SDL_GetTicks();
|
|
||||||
if (current_time > last_time + 2000) {
|
|
||||||
const auto results = system.GetAndResetPerfStats();
|
|
||||||
const auto title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)",
|
|
||||||
Common::g_build_fullname,
|
|
||||||
Common::g_scm_branch,
|
|
||||||
Common::g_scm_desc,
|
|
||||||
results.average_game_fps,
|
|
||||||
results.emulation_speed * 100.0);
|
|
||||||
SDL_SetWindowTitle(render_window, title.c_str());
|
|
||||||
last_time = current_time;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credits to Samantas5855 and others for this function.
|
// Credits to Samantas5855 and others for this function.
|
||||||
void EmuWindow_SDL3::SetWindowIcon() {
|
void EmuWindow_SDL3::SetWindowIcon() {
|
||||||
|
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||||
|
// Icons do not work yet
|
||||||
|
#else
|
||||||
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
||||||
if (yuzu_icon_stream == nullptr) {
|
if (yuzu_icon_stream == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
||||||
@@ -264,6 +243,7 @@ void EmuWindow_SDL3::SetWindowIcon() {
|
|||||||
// 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_DestroySurface(window_icon);
|
SDL_DestroySurface(window_icon);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||||
|
|||||||
@@ -9,11 +9,12 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/frontend/graphics_context.h"
|
#include "core/frontend/graphics_context.h"
|
||||||
|
|
||||||
struct SDL_Window;
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ public:
|
|||||||
bool IsShown() const override;
|
bool IsShown() const override;
|
||||||
|
|
||||||
/// Wait for the next event on the main thread.
|
/// Wait for the next event on the main thread.
|
||||||
void WaitEvent();
|
void OnEvent(SDL_Event& event);
|
||||||
|
|
||||||
// Sets the window icon from yuzu.bmp
|
// Sets the window icon from yuzu.bmp
|
||||||
void SetWindowIcon();
|
void SetWindowIcon();
|
||||||
@@ -80,6 +81,9 @@ protected:
|
|||||||
/// Called when a configuration change affects the minimal size of the window
|
/// Called when a configuration change affects the minimal size of the window
|
||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||||
|
|
||||||
|
/// Periodic changer of titlebar (independent of event loop)
|
||||||
|
SDL_TimerID titlebar_timer;
|
||||||
|
|
||||||
/// Is the window still open?
|
/// Is the window still open?
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
|
|
||||||
@@ -89,9 +93,6 @@ protected:
|
|||||||
/// Internal SDL3 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
|
|
||||||
u32 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;
|
||||||
|
|
||||||
|
|||||||
+81
-71
@@ -8,6 +8,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "common/settings_enums.h"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
#define SDL_MAIN_USE_CALLBACKS 1
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
@@ -39,9 +45,7 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// windows.h needs to be included before shellapi.h
|
// windows.h needs to be included before shellapi.h
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
#include "common/windows/timer_resolution.h"
|
#include "common/windows/timer_resolution.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -174,8 +178,14 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) {
|
|||||||
std::cout << std::endl << "* " << message << std::endl << std::endl;
|
std::cout << std::endl << "* " << message << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Application entry point
|
struct SdlState {
|
||||||
int main(int argc, char** argv) {
|
Core::System system{};
|
||||||
|
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
|
||||||
|
SdlState* state = new SdlState();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||||
freopen("CONOUT$", "wb", stdout);
|
freopen("CONOUT$", "wb", stdout);
|
||||||
@@ -193,7 +203,7 @@ int main(int argc, char** argv) {
|
|||||||
auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
|
auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
|
||||||
if (argv_w == nullptr) {
|
if (argv_w == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to get command line arguments");
|
LOG_CRITICAL(Frontend, "Failed to get command line arguments");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
@@ -247,7 +257,7 @@ int main(int argc, char** argv) {
|
|||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
PrintHelp(argv[0]);
|
PrintHelp(argv[0]);
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
case 'g':
|
case 'g':
|
||||||
filepath = std::string(optarg);
|
filepath = std::string(optarg);
|
||||||
break;
|
break;
|
||||||
@@ -264,7 +274,7 @@ int main(int argc, char** argv) {
|
|||||||
if (!std::regex_match(str_arg, re)) {
|
if (!std::regex_match(str_arg, re)) {
|
||||||
std::cout << "Wrong format for option --multiplayer\n";
|
std::cout << "Wrong format for option --multiplayer\n";
|
||||||
PrintHelp(argv[0]);
|
PrintHelp(argv[0]);
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
@@ -279,11 +289,11 @@ int main(int argc, char** argv) {
|
|||||||
std::regex nickname_re("^[a-zA-Z0-9._\\- ]+$");
|
std::regex nickname_re("^[a-zA-Z0-9._\\- ]+$");
|
||||||
if (!std::regex_match(nickname, nickname_re)) {
|
if (!std::regex_match(nickname, nickname_re)) {
|
||||||
LOG_ERROR(Frontend, "Nickname is not valid. Must be 4 to 20 alphanumeric characters");
|
LOG_ERROR(Frontend, "Nickname is not valid. Must be 4 to 20 alphanumeric characters");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
if (address.empty()) {
|
if (address.empty()) {
|
||||||
LOG_ERROR(Frontend, "Address to room must not be empty");
|
LOG_ERROR(Frontend, "Address to room must not be empty");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -296,7 +306,7 @@ int main(int argc, char** argv) {
|
|||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
PrintVersion();
|
PrintVersion();
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
case 'n':
|
case 'n':
|
||||||
force_null_render = true;
|
force_null_render = true;
|
||||||
break;
|
break;
|
||||||
@@ -358,79 +368,73 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
if (filepath.empty()) {
|
if (filepath.empty()) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
|
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System system{};
|
state->system.Initialize();
|
||||||
system.Initialize();
|
|
||||||
|
|
||||||
InputCommon::InputSubsystem input_subsystem{};
|
InputCommon::InputSubsystem input_subsystem{};
|
||||||
|
|
||||||
// Apply the command line arguments
|
// Apply the command line arguments
|
||||||
system.ApplySettings();
|
state->system.ApplySettings();
|
||||||
|
|
||||||
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
|
||||||
switch (Settings::values.renderer_backend.GetValue()) {
|
switch (Settings::values.renderer_backend.GetValue()) {
|
||||||
#ifdef HAS_OPENGL
|
#ifdef HAS_OPENGL
|
||||||
case Settings::RendererBackend::OpenGL_GLSL:
|
case Settings::RendererBackend::OpenGL_GLSL:
|
||||||
case Settings::RendererBackend::OpenGL_GLASM:
|
case Settings::RendererBackend::OpenGL_GLASM:
|
||||||
case Settings::RendererBackend::OpenGL_SPIRV:
|
case Settings::RendererBackend::OpenGL_SPIRV:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case Settings::RendererBackend::Vulkan:
|
case Settings::RendererBackend::Vulkan:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Null:
|
case Settings::RendererBackend::Null:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Frontend, "Invalid renderer backend");
|
LOG_CRITICAL(Frontend, "Invalid renderer backend");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Common::Windows::SetCurrentTimerResolutionToMaximum();
|
Common::Windows::SetCurrentTimerResolutionToMaximum();
|
||||||
system.CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution());
|
state->system.CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
state->system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||||
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
state->system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
|
state->system.GetFileSystemController().CreateFactories(*state->system.GetFilesystem());
|
||||||
system.GetUserChannel().clear();
|
state->system.GetUserChannel().clear();
|
||||||
|
|
||||||
Service::AM::FrontendAppletParameters load_parameters{
|
Service::AM::FrontendAppletParameters load_parameters{
|
||||||
.applet_id = Service::AM::AppletId::Application,
|
.applet_id = Service::AM::AppletId::Application,
|
||||||
};
|
};
|
||||||
const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)};
|
const Core::SystemResultStatus load_result = state->system.Load(*state->emu_window, filepath, load_parameters);
|
||||||
|
|
||||||
switch (load_result) {
|
switch (load_result) {
|
||||||
case Core::SystemResultStatus::ErrorGetLoader:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorLoader:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to load ROM!");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorNotInitialized:
|
|
||||||
LOG_CRITICAL(Frontend, "CPUCore not initialized");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorVideoCore:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::Success:
|
case Core::SystemResultStatus::Success:
|
||||||
break; // Expected case
|
break; // Expected case
|
||||||
|
case Core::SystemResultStatus::ErrorGetLoader:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorLoader:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to load ROM!");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorNotInitialized:
|
||||||
|
LOG_CRITICAL(Frontend, "CPUCore not initialized");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorVideoCore:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
default:
|
default:
|
||||||
if (static_cast<u32>(load_result) >
|
const u16 loader_id = u16(Core::SystemResultStatus::ErrorLoader);
|
||||||
static_cast<u32>(Core::SystemResultStatus::ErrorLoader)) {
|
const u16 error_id = u16(load_result) - loader_id;
|
||||||
const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
|
LOG_CRITICAL(Frontend,
|
||||||
const u16 error_id = static_cast<u16>(load_result) - loader_id;
|
"While attempting to load the ROM requested, an error occurred. Please "
|
||||||
LOG_CRITICAL(Frontend,
|
"refer to the Eden wiki for more information or the Eden discord for "
|
||||||
"While attempting to load the ROM requested, an error occurred. Please "
|
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
||||||
"refer to the Eden wiki for more information or the Eden discord for "
|
loader_id, error_id, Loader::ResultStatus(error_id));
|
||||||
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
return SDL_APP_FAILURE;
|
||||||
loader_id, error_id, static_cast<Loader::ResultStatus>(error_id));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_multiplayer) {
|
if (use_multiplayer) {
|
||||||
@@ -439,40 +443,46 @@ int main(int argc, char** argv) {
|
|||||||
member->BindOnStatusMessageReceived(OnStatusMessageReceived);
|
member->BindOnStatusMessageReceived(OnStatusMessageReceived);
|
||||||
member->BindOnStateChanged(OnStateChanged);
|
member->BindOnStateChanged(OnStateChanged);
|
||||||
member->BindOnError(OnNetworkError);
|
member->BindOnError(OnNetworkError);
|
||||||
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port,
|
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port, nickname);
|
||||||
nickname);
|
|
||||||
member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredIP, password);
|
member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredIP, password);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Network, "Could not access RoomMember");
|
LOG_ERROR(Network, "Could not access RoomMember");
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
|
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
|
||||||
system.GPU().Start();
|
state->system.GPU().Start();
|
||||||
system.GetCpuManager().OnGpuReady();
|
state->system.GetCpuManager().OnGpuReady();
|
||||||
|
|
||||||
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
||||||
system.Renderer().ReadRasterizer()->LoadDiskResources(
|
state->system.Renderer().ReadRasterizer()->LoadDiskResources(
|
||||||
system.GetApplicationProcessProgramID(), std::stop_token{},
|
state->system.GetApplicationProcessProgramID(), std::stop_token{},
|
||||||
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
|
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
system.RegisterExitCallback([&] {
|
// don't do anything, SDL3 already exists for us :D
|
||||||
// Just exit right away.
|
state->system.RegisterExitCallback([] {});
|
||||||
exit(0);
|
void(state->system.Run());
|
||||||
});
|
if (state->system.DebuggerEnabled())
|
||||||
void(system.Run());
|
state->system.InitializeDebugger();
|
||||||
if (system.DebuggerEnabled()) {
|
return SDL_APP_SUCCESS;
|
||||||
system.InitializeDebugger();
|
}
|
||||||
}
|
extern "C" SDL_AppResult SDL_AppIterate(void *appstate) {
|
||||||
while (emu_window->IsOpen()) {
|
SdlState *state = (SdlState *)appstate;
|
||||||
emu_window->WaitEvent();
|
return state->emu_window->IsOpen() ? SDL_APP_CONTINUE : SDL_APP_SUCCESS;
|
||||||
}
|
}
|
||||||
system.DetachDebugger();
|
extern "C" SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
|
||||||
void(system.Pause());
|
SdlState *state = (SdlState *)appstate;
|
||||||
system.ShutdownMainProcess();
|
state->emu_window->OnEvent(*event);
|
||||||
return 0;
|
return SDL_APP_SUCCESS;
|
||||||
|
}
|
||||||
|
extern "C" void SDL_AppQuit(void *appstate, SDL_AppResult result) {
|
||||||
|
SdlState *state = (SdlState *)appstate;
|
||||||
|
state->system.DetachDebugger();
|
||||||
|
void(state->system.Pause());
|
||||||
|
state->system.ShutdownMainProcess();
|
||||||
|
delete state;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VMA_IMPLEMENTATION
|
#define VMA_IMPLEMENTATION
|
||||||
|
|||||||
Reference in New Issue
Block a user