Merge pull request #9229 from JosJuice/android-emulationactivity-finish

Android: Handle failed boots correctly
This commit is contained in:
JosJuice 2020-11-09 10:46:08 +01:00 committed by GitHub
commit 72997c17d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 114 additions and 86 deletions

View File

@ -12,6 +12,8 @@ import android.util.DisplayMetrics;
import android.view.Surface; import android.view.Surface;
import android.widget.Toast; import android.widget.Toast;
import androidx.fragment.app.FragmentManager;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.dialogs.AlertMessage; import org.dolphinemu.dolphinemu.dialogs.AlertMessage;
import org.dolphinemu.dolphinemu.utils.CompressCallback; import org.dolphinemu.dolphinemu.utils.CompressCallback;
@ -403,15 +405,13 @@ public final class NativeLibrary
*/ */
public static native void StopEmulation(); public static native void StopEmulation();
public static native boolean IsBooting();
public static native void WaitUntilDoneBooting();
/** /**
* Returns true if emulation is running (or is paused). * Returns true if emulation is running (or is paused).
*/ */
public static native boolean IsRunning(); public static native boolean IsRunning();
public static native boolean IsRunningAndStarted();
/** /**
* Enables or disables CPU block profiling * Enables or disables CPU block profiling
* *
@ -487,7 +487,7 @@ public final class NativeLibrary
private static native String GetCurrentTitleDescriptionUnchecked(); private static native String GetCurrentTitleDescriptionUnchecked();
public static boolean displayAlertMsg(final String caption, final String text, public static boolean displayAlertMsg(final String caption, final String text,
final boolean yesNo, final boolean isWarning) final boolean yesNo, final boolean isWarning, final boolean nonBlocking)
{ {
Log.error("[NativeLibrary] Alert: " + text); Log.error("[NativeLibrary] Alert: " + text);
final EmulationActivity emulationActivity = sEmulationActivity.get(); final EmulationActivity emulationActivity = sEmulationActivity.get();
@ -498,10 +498,9 @@ public final class NativeLibrary
} }
else else
{ {
// AlertMessages while the core is booting will deadlock if WaitUntilDoneBooting is called. // We can't use AlertMessages unless we have a non-null activity reference
// We also can't use AlertMessages unless we have a non-null activity reference. // and are allowed to block. As a fallback, we can use toasts.
// As a fallback, we use toasts instead. if (emulationActivity == null || nonBlocking)
if (emulationActivity == null || IsBooting())
{ {
new Handler(Looper.getMainLooper()).post( new Handler(Looper.getMainLooper()).post(
() -> Toast.makeText(DolphinApplication.getAppContext(), text, Toast.LENGTH_LONG) () -> Toast.makeText(DolphinApplication.getAppContext(), text, Toast.LENGTH_LONG)
@ -511,9 +510,22 @@ public final class NativeLibrary
{ {
sIsShowingAlertMessage = true; sIsShowingAlertMessage = true;
emulationActivity.runOnUiThread( emulationActivity.runOnUiThread(() ->
() -> AlertMessage.newInstance(caption, text, yesNo, isWarning) {
.show(emulationActivity.getSupportFragmentManager(), "AlertMessage")); FragmentManager fragmentManager = emulationActivity.getSupportFragmentManager();
if (fragmentManager.isStateSaved())
{
// The activity is being destroyed, so we can't use it to display an AlertMessage.
// Fall back to a toast.
Toast.makeText(emulationActivity, text, Toast.LENGTH_LONG).show();
NotifyAlertMessageLock();
}
else
{
AlertMessage.newInstance(caption, text, yesNo, isWarning)
.show(fragmentManager, "AlertMessage");
}
});
// Wait for the lock to notify that it is complete. // Wait for the lock to notify that it is complete.
synchronized (sAlertMessageLock) synchronized (sAlertMessageLock)
@ -563,6 +575,20 @@ public final class NativeLibrary
sEmulationActivity.clear(); sEmulationActivity.clear();
} }
public static void finishEmulationActivity()
{
final EmulationActivity emulationActivity = sEmulationActivity.get();
if (emulationActivity == null)
{
Log.warning("[NativeLibrary] EmulationActivity is null.");
}
else
{
Log.verbose("[NativeLibrary] Finishing EmulationActivity.");
emulationActivity.runOnUiThread(emulationActivity::finish);
}
}
public static void updateTouchPointer() public static void updateTouchPointer()
{ {
final EmulationActivity emulationActivity = sEmulationActivity.get(); final EmulationActivity emulationActivity = sEmulationActivity.get();

View File

@ -81,10 +81,12 @@ public final class EmulationActivity extends AppCompatActivity
private String[] mPaths; private String[] mPaths;
private boolean mIgnoreWarnings; private boolean mIgnoreWarnings;
private static boolean sUserPausedEmulation; private static boolean sUserPausedEmulation;
private boolean mMenuToastShown;
public static final String EXTRA_SELECTED_GAMES = "SelectedGames"; public static final String EXTRA_SELECTED_GAMES = "SelectedGames";
public static final String EXTRA_IGNORE_WARNINGS = "IgnoreWarnings"; public static final String EXTRA_IGNORE_WARNINGS = "IgnoreWarnings";
public static final String EXTRA_USER_PAUSED_EMULATION = "sUserPausedEmulation"; public static final String EXTRA_USER_PAUSED_EMULATION = "sUserPausedEmulation";
public static final String EXTRA_MENU_TOAST_SHOWN = "MenuToastShown";
@Retention(SOURCE) @Retention(SOURCE)
@IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE, @IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE,
@ -212,8 +214,8 @@ public final class EmulationActivity extends AppCompatActivity
mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES); mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES);
mIgnoreWarnings = gameToEmulate.getBooleanExtra(EXTRA_IGNORE_WARNINGS, false); mIgnoreWarnings = gameToEmulate.getBooleanExtra(EXTRA_IGNORE_WARNINGS, false);
sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false); sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false);
mMenuToastShown = false;
activityRecreated = false; activityRecreated = false;
Toast.makeText(this, R.string.emulation_menu_help, Toast.LENGTH_LONG).show();
} }
else else
{ {
@ -260,8 +262,9 @@ public final class EmulationActivity extends AppCompatActivity
mEmulationFragment.saveTemporaryState(); mEmulationFragment.saveTemporaryState();
} }
outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths); outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths);
outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, mIgnoreWarnings); outState.putBoolean(EXTRA_IGNORE_WARNINGS, mIgnoreWarnings);
outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, sUserPausedEmulation); outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, sUserPausedEmulation);
outState.putBoolean(EXTRA_MENU_TOAST_SHOWN, mMenuToastShown);
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@ -270,6 +273,7 @@ public final class EmulationActivity extends AppCompatActivity
mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES); mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES);
mIgnoreWarnings = savedInstanceState.getBoolean(EXTRA_IGNORE_WARNINGS); mIgnoreWarnings = savedInstanceState.getBoolean(EXTRA_IGNORE_WARNINGS);
sUserPausedEmulation = savedInstanceState.getBoolean(EXTRA_USER_PAUSED_EMULATION); sUserPausedEmulation = savedInstanceState.getBoolean(EXTRA_USER_PAUSED_EMULATION);
mMenuToastShown = savedInstanceState.getBoolean(EXTRA_MENU_TOAST_SHOWN);
} }
@Override @Override
@ -306,6 +310,13 @@ public final class EmulationActivity extends AppCompatActivity
public void onTitleChanged() public void onTitleChanged()
{ {
if (!mMenuToastShown)
{
// The reason why this doesn't run earlier is because we want to be sure the boot succeeded.
Toast.makeText(this, R.string.emulation_menu_help, Toast.LENGTH_LONG).show();
mMenuToastShown = true;
}
setTitle(NativeLibrary.GetCurrentTitleDescription()); setTitle(NativeLibrary.GetCurrentTitleDescription());
updateMotionListener(); updateMotionListener();
@ -342,7 +353,6 @@ public final class EmulationActivity extends AppCompatActivity
if (keyCode == KeyEvent.KEYCODE_BACK) if (keyCode == KeyEvent.KEYCODE_BACK)
{ {
mEmulationFragment.stopEmulation(); mEmulationFragment.stopEmulation();
finish();
return true; return true;
} }
return super.onKeyLongPress(keyCode, event); return super.onKeyLongPress(keyCode, event);
@ -617,7 +627,6 @@ public final class EmulationActivity extends AppCompatActivity
case MENU_ACTION_EXIT: case MENU_ACTION_EXIT:
mEmulationFragment.stopEmulation(); mEmulationFragment.stopEmulation();
finish();
break; break;
} }
} }

View File

@ -330,16 +330,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
mSurface = null; mSurface = null;
Log.debug("[EmulationFragment] Surface destroyed."); Log.debug("[EmulationFragment] Surface destroyed.");
if (state != State.STOPPED && !NativeLibrary.IsShowingAlertMessage())
{
// In order to avoid dereferencing nullptr, we must not destroy the surface while booting
// the core, so wait here if necessary. An easy (but not 100% consistent) way to reach
// this method while the core is booting is by having landscape orientation lock enabled
// and starting emulation while the phone is in portrait mode, leading to the activity
// being recreated very soon after NativeLibrary.Run has been called.
NativeLibrary.WaitUntilDoneBooting();
}
NativeLibrary.SurfaceDestroyed(); NativeLibrary.SurfaceDestroyed();
} }
} }

View File

@ -148,7 +148,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
public void initTouchPointer() public void initTouchPointer()
{ {
// Check if we have all the data we need yet // Check if we have all the data we need yet
boolean aspectRatioAvailable = NativeLibrary.IsRunning() && !NativeLibrary.IsBooting(); boolean aspectRatioAvailable = NativeLibrary.IsRunningAndStarted();
if (!aspectRatioAvailable || mSurfacePosition == null) if (!aspectRatioAvailable || mSurfacePosition == null)
return; return;

View File

@ -15,6 +15,7 @@ static jmethodID s_display_alert_msg;
static jmethodID s_do_rumble; static jmethodID s_do_rumble;
static jmethodID s_update_touch_pointer; static jmethodID s_update_touch_pointer;
static jmethodID s_on_title_changed; static jmethodID s_on_title_changed;
static jmethodID s_finish_emulation_activity;
static jclass s_game_file_class; static jclass s_game_file_class;
static jfieldID s_game_file_pointer; static jfieldID s_game_file_pointer;
@ -94,6 +95,11 @@ jmethodID GetOnTitleChanged()
return s_on_title_changed; return s_on_title_changed;
} }
jmethodID GetFinishEmulationActivity()
{
return s_finish_emulation_activity;
}
jclass GetAnalyticsClass() jclass GetAnalyticsClass()
{ {
return s_analytics_class; return s_analytics_class;
@ -216,11 +222,13 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
const jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary"); const jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class)); s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg", s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
"(Ljava/lang/String;Ljava/lang/String;ZZ)Z"); "(Ljava/lang/String;Ljava/lang/String;ZZZ)Z");
s_do_rumble = env->GetStaticMethodID(s_native_library_class, "rumble", "(ID)V"); s_do_rumble = env->GetStaticMethodID(s_native_library_class, "rumble", "(ID)V");
s_update_touch_pointer = s_update_touch_pointer =
env->GetStaticMethodID(s_native_library_class, "updateTouchPointer", "()V"); env->GetStaticMethodID(s_native_library_class, "updateTouchPointer", "()V");
s_on_title_changed = env->GetStaticMethodID(s_native_library_class, "onTitleChanged", "()V"); s_on_title_changed = env->GetStaticMethodID(s_native_library_class, "onTitleChanged", "()V");
s_finish_emulation_activity =
env->GetStaticMethodID(s_native_library_class, "finishEmulationActivity", "()V");
env->DeleteLocalRef(native_library_class); env->DeleteLocalRef(native_library_class);
const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile"); const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile");

View File

@ -15,6 +15,7 @@ jmethodID GetDisplayAlertMsg();
jmethodID GetDoRumble(); jmethodID GetDoRumble();
jmethodID GetUpdateTouchPointer(); jmethodID GetUpdateTouchPointer();
jmethodID GetOnTitleChanged(); jmethodID GetOnTitleChanged();
jmethodID GetFinishEmulationActivity();
jclass GetAnalyticsClass(); jclass GetAnalyticsClass();
jmethodID GetSendAnalyticsReport(); jmethodID GetSendAnalyticsReport();

View File

@ -77,7 +77,12 @@ ANativeWindow* s_surf;
// sequentially for access. // sequentially for access.
std::mutex s_host_identity_lock; std::mutex s_host_identity_lock;
Common::Event s_update_main_frame_event; Common::Event s_update_main_frame_event;
Common::Event s_emulation_end_event;
// This exists to prevent surfaces from being destroyed during the boot process,
// as that can lead to the boot process dereferencing nullptr.
std::mutex s_surface_lock;
bool s_need_nonblocking_alert_msg;
bool s_have_wm_user_stop = false; bool s_have_wm_user_stop = false;
bool s_game_metadata_is_valid = false; bool s_game_metadata_is_valid = false;
} // Anonymous namespace } // Anonymous namespace
@ -160,9 +165,10 @@ static bool MsgAlert(const char* caption, const char* text, bool yes_no, Common:
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
// Execute the Java method. // Execute the Java method.
jboolean result = env->CallStaticBooleanMethod( jboolean result =
IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), ToJString(env, caption), env->CallStaticBooleanMethod(IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(),
ToJString(env, text), yes_no ? JNI_TRUE : JNI_FALSE, style == Common::MsgType::Warning); ToJString(env, caption), ToJString(env, text), yes_no,
style == Common::MsgType::Warning, s_need_nonblocking_alert_msg);
return result != JNI_FALSE; return result != JNI_FALSE;
} }
@ -210,33 +216,22 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulati
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv*, jclass) JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv*, jclass)
{ {
{ std::lock_guard<std::mutex> guard(s_host_identity_lock);
std::lock_guard<std::mutex> guard(s_host_identity_lock); Core::Stop();
s_emulation_end_event.Reset();
Core::Stop();
// Kick the waiting event // Kick the waiting event
s_update_main_frame_event.Set(); s_update_main_frame_event.Set();
}
// Wait for shutdown, to avoid accessing the config at the same time as the shutdown code
s_emulation_end_event.Wait();
}
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsBooting(JNIEnv*, jclass)
{
return static_cast<jboolean>(Core::IsBooting());
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv*,
jclass)
{
Core::WaitUntilDoneBooting();
} }
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv*, jclass) JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv*, jclass)
{ {
return Core::IsRunning(); return static_cast<jboolean>(Core::IsRunning());
}
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndStarted(JNIEnv*,
jclass)
{
return static_cast<jboolean>(Core::IsRunningAndStarted());
} }
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent( JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
@ -398,6 +393,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
jclass, jclass,
jobject surf) jobject surf)
{ {
std::lock_guard<std::mutex> guard(s_surface_lock);
s_surf = ANativeWindow_fromSurface(env, surf); s_surf = ANativeWindow_fromSurface(env, surf);
if (s_surf == nullptr) if (s_surf == nullptr)
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null."); __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
@ -409,6 +406,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*,
jclass) jclass)
{ {
std::lock_guard<std::mutex> guard(s_surface_lock);
if (g_renderer) if (g_renderer)
g_renderer->ChangeSurface(nullptr); g_renderer->ChangeSurface(nullptr);
@ -487,7 +486,7 @@ static void Run(JNIEnv* env, const std::vector<std::string>& paths,
ASSERT(!paths.empty()); ASSERT(!paths.empty());
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str()); __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str());
std::unique_lock<std::mutex> guard(s_host_identity_lock); std::unique_lock<std::mutex> host_identity_guard(s_host_identity_lock);
WiimoteReal::InitAdapterClass(); WiimoteReal::InitAdapterClass();
@ -500,24 +499,41 @@ static void Run(JNIEnv* env, const std::vector<std::string>& paths,
WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf); WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf);
wsi.render_surface_scale = GetRenderSurfaceScale(env); wsi.render_surface_scale = GetRenderSurfaceScale(env);
// No use running the loop when booting fails s_need_nonblocking_alert_msg = true;
if (BootManager::BootCore(std::move(boot), wsi)) std::unique_lock<std::mutex> surface_guard(s_surface_lock);
bool successful_boot = BootManager::BootCore(std::move(boot), wsi);
if (successful_boot)
{ {
ButtonManager::Init(SConfig::GetInstance().GetGameID()); ButtonManager::Init(SConfig::GetInstance().GetGameID());
static constexpr int TIMEOUT = 10000; static constexpr int TIMEOUT = 10000;
static constexpr int WAIT_STEP = 25; static constexpr int WAIT_STEP = 25;
int time_waited = 0; int time_waited = 0;
// A Core::CORE_ERROR state would be helpful here. // A Core::CORE_ERROR state would be helpful here.
while (!Core::IsRunning() && time_waited < TIMEOUT && !s_have_wm_user_stop) while (!Core::IsRunningAndStarted())
{ {
if (time_waited >= TIMEOUT || s_have_wm_user_stop)
{
successful_boot = false;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP)); std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP));
time_waited += WAIT_STEP; time_waited += WAIT_STEP;
} }
while (Core::IsRunning()) }
s_need_nonblocking_alert_msg = false;
surface_guard.unlock();
if (successful_boot)
{
while (Core::IsRunningAndStarted())
{ {
guard.unlock(); host_identity_guard.unlock();
s_update_main_frame_event.Wait(); s_update_main_frame_event.Wait();
guard.lock(); host_identity_guard.lock();
Core::HostDispatchJobs(); Core::HostDispatchJobs();
} }
} }
@ -525,15 +541,10 @@ static void Run(JNIEnv* env, const std::vector<std::string>& paths,
s_game_metadata_is_valid = false; s_game_metadata_is_valid = false;
Core::Shutdown(); Core::Shutdown();
ButtonManager::Shutdown(); ButtonManager::Shutdown();
guard.unlock(); host_identity_guard.unlock();
if (s_surf) env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
{ IDCache::GetFinishEmulationActivity());
ANativeWindow_release(s_surf);
s_surf = nullptr;
}
s_emulation_end_event.Set();
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2( JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(

View File

@ -102,7 +102,6 @@ static bool s_is_stopping = false;
static bool s_hardware_initialized = false; static bool s_hardware_initialized = false;
static bool s_is_started = false; static bool s_is_started = false;
static Common::Flag s_is_booting; static Common::Flag s_is_booting;
static Common::Event s_done_booting;
static std::thread s_emu_thread; static std::thread s_emu_thread;
static StateChangedCallbackFunc s_on_state_changed_callback; static StateChangedCallbackFunc s_on_state_changed_callback;
@ -175,11 +174,6 @@ void DisplayMessage(std::string message, int time_in_ms)
OSD::AddMessage(std::move(message), time_in_ms); OSD::AddMessage(std::move(message), time_in_ms);
} }
bool IsBooting()
{
return s_is_booting.IsSet() || !s_hardware_initialized;
}
bool IsRunning() bool IsRunning()
{ {
return (GetState() != State::Uninitialized || s_hardware_initialized) && !s_is_stopping; return (GetState() != State::Uninitialized || s_hardware_initialized) && !s_is_stopping;
@ -249,7 +243,6 @@ bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
g_video_backend->PrepareWindow(prepared_wsi); g_video_backend->PrepareWindow(prepared_wsi);
// Start the emu thread // Start the emu thread
s_done_booting.Reset();
s_is_booting.Set(); s_is_booting.Set();
s_emu_thread = std::thread(EmuThread, std::move(boot), prepared_wsi); s_emu_thread = std::thread(EmuThread, std::move(boot), prepared_wsi);
return true; return true;
@ -435,7 +428,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
s_on_state_changed_callback(State::Starting); s_on_state_changed_callback(State::Starting);
Common::ScopeGuard flag_guard{[] { Common::ScopeGuard flag_guard{[] {
s_is_booting.Clear(); s_is_booting.Clear();
s_done_booting.Set();
s_is_started = false; s_is_started = false;
s_is_stopping = false; s_is_stopping = false;
s_wants_determinism = false; s_wants_determinism = false;
@ -568,7 +560,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
// The hardware is initialized. // The hardware is initialized.
s_hardware_initialized = true; s_hardware_initialized = true;
s_is_booting.Clear(); s_is_booting.Clear();
s_done_booting.Set();
// Set execution state to known values (CPU/FIFO/Audio Paused) // Set execution state to known values (CPU/FIFO/Audio Paused)
CPU::Break(); CPU::Break();
@ -692,12 +683,6 @@ State GetState()
return State::Uninitialized; return State::Uninitialized;
} }
void WaitUntilDoneBooting()
{
if (IsBooting())
s_done_booting.Wait();
}
static std::string GenerateScreenshotFolderPath() static std::string GenerateScreenshotFolderPath()
{ {
const std::string& gameId = SConfig::GetInstance().GetGameID(); const std::string& gameId = SConfig::GetInstance().GetGameID();

View File

@ -99,7 +99,6 @@ void UndeclareAsCPUThread();
std::string StopMessage(bool main_thread, std::string_view message); std::string StopMessage(bool main_thread, std::string_view message);
bool IsBooting();
bool IsRunning(); bool IsRunning();
bool IsRunningAndStarted(); // is running and the CPU loop has been entered bool IsRunningAndStarted(); // is running and the CPU loop has been entered
bool IsRunningInCurrentThread(); // this tells us whether we are running in the CPU thread. bool IsRunningInCurrentThread(); // this tells us whether we are running in the CPU thread.
@ -111,7 +110,6 @@ bool WantsDeterminism();
// [NOT THREADSAFE] For use by Host only // [NOT THREADSAFE] For use by Host only
void SetState(State state); void SetState(State state);
State GetState(); State GetState();
void WaitUntilDoneBooting();
void SaveScreenShot(); void SaveScreenShot();
void SaveScreenShot(std::string_view name); void SaveScreenShot(std::string_view name);