mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
GPU: Allow closing window/app to interrupt shader compilation
This commit is contained in:
parent
413e52b38d
commit
24c2165bb3
|
@ -365,13 +365,17 @@ void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulat
|
||||||
if (!m_surface)
|
if (!m_surface)
|
||||||
{
|
{
|
||||||
Log_ErrorPrint("Emulation thread started without surface set.");
|
Log_ErrorPrint("Emulation thread started without surface set.");
|
||||||
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateImGuiContext();
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
m_emulation_thread_running.store(true);
|
||||||
m_emulation_activity_object = emulation_activity;
|
m_emulation_activity_object = emulation_activity;
|
||||||
m_emulation_thread_id = std::this_thread::get_id();
|
m_emulation_thread_id = std::this_thread::get_id();
|
||||||
|
}
|
||||||
|
CreateImGuiContext();
|
||||||
ApplySettings(true);
|
ApplySettings(true);
|
||||||
|
|
||||||
// Boot system.
|
// Boot system.
|
||||||
|
@ -398,24 +402,31 @@ void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulat
|
||||||
|
|
||||||
PowerOffSystem();
|
PowerOffSystem();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Drain any callbacks so we don't leave things in a screwed-up state for next boot.
|
||||||
{
|
{
|
||||||
ReportFormattedError("Failed to boot system on emulation thread (file:%s).", boot_params.filename.c_str());
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
while (!m_callback_queue.empty())
|
||||||
|
{
|
||||||
|
auto callback = std::move(m_callback_queue.front());
|
||||||
|
m_callback_queue.pop_front();
|
||||||
|
lock.unlock();
|
||||||
|
callback();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
m_emulation_thread_running.store(false);
|
||||||
|
m_emulation_thread_id = {};
|
||||||
|
m_emulation_activity_object = {};
|
||||||
|
m_callbacks_outstanding.store(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped);
|
||||||
|
|
||||||
DestroyImGuiContext();
|
DestroyImGuiContext();
|
||||||
m_emulation_activity_object = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
|
void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
|
||||||
{
|
{
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
|
||||||
m_emulation_thread_running.store(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
|
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -440,7 +451,6 @@ void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
|
||||||
|
|
||||||
if (m_emulation_thread_stop_request.load())
|
if (m_emulation_thread_stop_request.load())
|
||||||
{
|
{
|
||||||
m_emulation_thread_running.store(false);
|
|
||||||
m_emulation_thread_stop_request.store(false);
|
m_emulation_thread_stop_request.store(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1059,6 +1069,13 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, j
|
||||||
if (surface && !native_surface)
|
if (surface && !native_surface)
|
||||||
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
||||||
|
|
||||||
|
if (!surface && System::GetState() == System::State::Starting)
|
||||||
|
{
|
||||||
|
// User switched away from the app while it was compiling shaders.
|
||||||
|
Log_ErrorPrintf("Surface destroyed while starting, cancelling");
|
||||||
|
System::CancelPendingStartup();
|
||||||
|
}
|
||||||
|
|
||||||
// We should wait for the emu to finish if the surface is being destroyed or changed.
|
// We should wait for the emu to finish if the surface is being destroyed or changed.
|
||||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
const bool block = (!native_surface || native_surface != hi->GetSurface());
|
const bool block = (!native_surface || native_surface != hi->GetSurface());
|
||||||
|
@ -1376,6 +1393,12 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveState, jobject obj, jboole
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveResumeState, jobject obj, jboolean wait_for_completion)
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveResumeState, jobject obj, jboolean wait_for_completion)
|
||||||
{
|
{
|
||||||
|
if (!System::IsValid() || System::GetState() == System::State::Starting)
|
||||||
|
{
|
||||||
|
// This gets called when the surface is destroyed, which can happen while starting.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
hi->RunOnEmulationThread([hi]() { hi->SaveResumeSaveState(); }, wait_for_completion);
|
hi->RunOnEmulationThread([hi]() { hi->SaveResumeSaveState(); }, wait_for_completion);
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,6 +509,10 @@ bool GPU_HW_D3D11::CompileShaders()
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
progress_value++; \
|
progress_value++; \
|
||||||
|
if (System::IsStartupCancelled()) \
|
||||||
|
{ \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
||||||
{ \
|
{ \
|
||||||
compile_time.Reset(); \
|
compile_time.Reset(); \
|
||||||
|
|
|
@ -519,6 +519,10 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
progress_value++; \
|
progress_value++; \
|
||||||
|
if (System::IsStartupCancelled()) \
|
||||||
|
{ \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
||||||
{ \
|
{ \
|
||||||
compile_time.Reset(); \
|
compile_time.Reset(); \
|
||||||
|
|
|
@ -829,6 +829,10 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
progress_value++; \
|
progress_value++; \
|
||||||
|
if (System::IsStartupCancelled()) \
|
||||||
|
{ \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
if (compile_time.GetTimeSeconds() >= 1.0f) \
|
||||||
{ \
|
{ \
|
||||||
compile_time.Reset(); \
|
compile_time.Reset(); \
|
||||||
|
|
|
@ -114,9 +114,13 @@ bool HostInterface::BootSystem(const SystemBootParameters& parameters)
|
||||||
CreateAudioStream();
|
CreateAudioStream();
|
||||||
|
|
||||||
if (!System::Boot(parameters))
|
if (!System::Boot(parameters))
|
||||||
|
{
|
||||||
|
if (!System::IsStartupCancelled())
|
||||||
{
|
{
|
||||||
ReportFormattedError(
|
ReportFormattedError(
|
||||||
g_host_interface->TranslateString("System", "System failed to boot. The log may contain more information."));
|
g_host_interface->TranslateString("System", "System failed to boot. The log may contain more information."));
|
||||||
|
}
|
||||||
|
|
||||||
OnSystemDestroyed();
|
OnSystemDestroyed();
|
||||||
m_audio_stream.reset();
|
m_audio_stream.reset();
|
||||||
ReleaseHostDisplay();
|
ReleaseHostDisplay();
|
||||||
|
|
|
@ -85,6 +85,7 @@ static void UpdateRunningGame(const char* path, CDImage* image);
|
||||||
static bool CheckForSBIFile(CDImage* image);
|
static bool CheckForSBIFile(CDImage* image);
|
||||||
|
|
||||||
static State s_state = State::Shutdown;
|
static State s_state = State::Shutdown;
|
||||||
|
static std::atomic_bool s_startup_cancelled{false};
|
||||||
|
|
||||||
static ConsoleRegion s_region = ConsoleRegion::NTSC_U;
|
static ConsoleRegion s_region = ConsoleRegion::NTSC_U;
|
||||||
TickCount g_ticks_per_second = MASTER_CLOCK;
|
TickCount g_ticks_per_second = MASTER_CLOCK;
|
||||||
|
@ -173,6 +174,17 @@ bool IsValid()
|
||||||
return s_state != State::Shutdown && s_state != State::Starting;
|
return s_state != State::Shutdown && s_state != State::Starting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsStartupCancelled()
|
||||||
|
{
|
||||||
|
return s_startup_cancelled.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CancelPendingStartup()
|
||||||
|
{
|
||||||
|
if (s_state == State::Starting)
|
||||||
|
s_startup_cancelled.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
ConsoleRegion GetRegion()
|
ConsoleRegion GetRegion()
|
||||||
{
|
{
|
||||||
return s_region;
|
return s_region;
|
||||||
|
@ -584,7 +596,10 @@ bool RecreateGPU(GPURenderer renderer, bool update_display /* = true*/)
|
||||||
g_gpu.reset();
|
g_gpu.reset();
|
||||||
if (!CreateGPU(renderer))
|
if (!CreateGPU(renderer))
|
||||||
{
|
{
|
||||||
Panic("Failed to recreate GPU");
|
if (!IsStartupCancelled())
|
||||||
|
g_host_interface->ReportError("Failed to recreate GPU.");
|
||||||
|
|
||||||
|
System::Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,6 +643,7 @@ bool Boot(const SystemBootParameters& params)
|
||||||
Assert(s_state == State::Shutdown);
|
Assert(s_state == State::Shutdown);
|
||||||
Assert(s_media_playlist.empty());
|
Assert(s_media_playlist.empty());
|
||||||
s_state = State::Starting;
|
s_state = State::Starting;
|
||||||
|
s_startup_cancelled.store(false);
|
||||||
s_region = g_settings.region;
|
s_region = g_settings.region;
|
||||||
|
|
||||||
if (params.state_stream)
|
if (params.state_stream)
|
||||||
|
@ -833,6 +849,13 @@ bool Initialize(bool force_software_renderer)
|
||||||
if (!CreateGPU(force_software_renderer ? GPURenderer::Software : g_settings.gpu_renderer))
|
if (!CreateGPU(force_software_renderer ? GPURenderer::Software : g_settings.gpu_renderer))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Was startup cancelled? (e.g. shading compilers took too long and the user closed the application)
|
||||||
|
if (IsStartupCancelled())
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// CPU code cache must happen after GPU, because it might steal our address space.
|
// CPU code cache must happen after GPU, because it might steal our address space.
|
||||||
CPU::CodeCache::Initialize();
|
CPU::CodeCache::Initialize();
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,9 @@ bool IsPaused();
|
||||||
bool IsShutdown();
|
bool IsShutdown();
|
||||||
bool IsValid();
|
bool IsValid();
|
||||||
|
|
||||||
|
bool IsStartupCancelled();
|
||||||
|
void CancelPendingStartup();
|
||||||
|
|
||||||
ConsoleRegion GetRegion();
|
ConsoleRegion GetRegion();
|
||||||
bool IsPALRegion();
|
bool IsPALRegion();
|
||||||
|
|
||||||
|
|
|
@ -825,6 +825,7 @@ void QtHostInterface::powerOffSystem()
|
||||||
{
|
{
|
||||||
if (!isOnWorkerThread())
|
if (!isOnWorkerThread())
|
||||||
{
|
{
|
||||||
|
System::CancelPendingStartup();
|
||||||
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -839,6 +840,7 @@ void QtHostInterface::powerOffSystemWithoutSaving()
|
||||||
{
|
{
|
||||||
if (!isOnWorkerThread())
|
if (!isOnWorkerThread())
|
||||||
{
|
{
|
||||||
|
System::CancelPendingStartup();
|
||||||
QMetaObject::invokeMethod(this, "powerOffSystemWithoutSaving", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "powerOffSystemWithoutSaving", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -849,9 +851,14 @@ void QtHostInterface::powerOffSystemWithoutSaving()
|
||||||
void QtHostInterface::synchronousPowerOffSystem()
|
void QtHostInterface::synchronousPowerOffSystem()
|
||||||
{
|
{
|
||||||
if (!isOnWorkerThread())
|
if (!isOnWorkerThread())
|
||||||
|
{
|
||||||
|
System::CancelPendingStartup();
|
||||||
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::BlockingQueuedConnection);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
powerOffSystem();
|
powerOffSystem();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHostInterface::resetSystem()
|
void QtHostInterface::resetSystem()
|
||||||
|
|
Loading…
Reference in a new issue