Merge pull request #8452 from JosJuice/android-emulationactivity-rotation-crash
Android: Replace emulation rotation crash workaround with proper fix
This commit is contained in:
commit
18ba1fd723
|
@ -400,6 +400,8 @@ public final class NativeLibrary
|
||||||
*/
|
*/
|
||||||
public static native void StopEmulation();
|
public static native void StopEmulation();
|
||||||
|
|
||||||
|
public static native void WaitUntilDoneBooting();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if emulation is running (or is paused).
|
* Returns true if emulation is running (or is paused).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -235,10 +235,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// Find the EmulationFragment
|
|
||||||
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
|
||||||
.findFragmentById(R.id.frame_emulation_fragment);
|
|
||||||
|
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
{
|
{
|
||||||
// Get params we were passed
|
// Get params we were passed
|
||||||
|
@ -251,9 +247,7 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Could have recreated the activity(rotate) before creating the fragment. If the fragment
|
activityRecreated = true;
|
||||||
// doesn't exist, treat this as a new start.
|
|
||||||
activityRecreated = mEmulationFragment != null;
|
|
||||||
restoreState(savedInstanceState);
|
restoreState(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,9 +305,10 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(mDeviceHasTouchScreen && lockLandscape &&
|
// Find or create the EmulationFragment
|
||||||
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) &&
|
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
||||||
mEmulationFragment == null)
|
.findFragmentById(R.id.frame_emulation_fragment);
|
||||||
|
if (mEmulationFragment == null)
|
||||||
{
|
{
|
||||||
mEmulationFragment = EmulationFragment.newInstance(mPaths);
|
mEmulationFragment = EmulationFragment.newInstance(mPaths);
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
|
|
@ -316,8 +316,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
state = State.PAUSED;
|
state = State.PAUSED;
|
||||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
Log.debug("[EmulationFragment] Pausing emulation.");
|
||||||
|
|
||||||
// Release the surface before pausing, since emulation has to be running for that.
|
|
||||||
NativeLibrary.SurfaceDestroyed();
|
|
||||||
NativeLibrary.PauseEmulation();
|
NativeLibrary.PauseEmulation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -381,19 +379,17 @@ 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.RUNNING)
|
if (state != State.STOPPED)
|
||||||
{
|
{
|
||||||
NativeLibrary.SurfaceDestroyed();
|
// In order to avoid dereferencing nullptr, we must not destroy the surface while booting
|
||||||
state = State.PAUSED;
|
// 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
|
||||||
else if (state == State.PAUSED)
|
// and starting emulation while the phone is in portrait mode, leading to the activity
|
||||||
{
|
// being recreated very soon after NativeLibrary.Run has been called.
|
||||||
Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
|
NativeLibrary.WaitUntilDoneBooting();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeLibrary.SurfaceDestroyed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulati
|
||||||
jobject obj);
|
jobject obj);
|
||||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
|
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
|
||||||
jobject obj);
|
jobject obj);
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj);
|
||||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
|
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
|
||||||
jobject obj);
|
jobject obj);
|
||||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
|
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
|
||||||
|
@ -283,6 +285,12 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulatio
|
||||||
s_update_main_frame_event.Set(); // Kick the waiting event
|
s_update_main_frame_event.Set(); // Kick the waiting event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj)
|
||||||
|
{
|
||||||
|
Core::WaitUntilDoneBooting();
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
|
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
|
||||||
jobject obj)
|
jobject obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,6 +94,7 @@ 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;
|
||||||
|
|
||||||
|
@ -236,6 +237,8 @@ bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
|
||||||
g_video_backend->PrepareWindow(wsi);
|
g_video_backend->PrepareWindow(wsi);
|
||||||
|
|
||||||
// Start the emu thread
|
// Start the emu thread
|
||||||
|
s_done_booting.Reset();
|
||||||
|
s_is_booting.Set();
|
||||||
s_emu_thread = std::thread(EmuThread, std::move(boot), wsi);
|
s_emu_thread = std::thread(EmuThread, std::move(boot), wsi);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -412,11 +415,11 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
|
||||||
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi)
|
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi)
|
||||||
{
|
{
|
||||||
const SConfig& core_parameter = SConfig::GetInstance();
|
const SConfig& core_parameter = SConfig::GetInstance();
|
||||||
s_is_booting.Set();
|
|
||||||
if (s_on_state_changed_callback)
|
if (s_on_state_changed_callback)
|
||||||
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;
|
||||||
|
@ -539,6 +542,7 @@ 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();
|
||||||
|
@ -662,6 +666,12 @@ State GetState()
|
||||||
return State::Uninitialized;
|
return State::Uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaitUntilDoneBooting()
|
||||||
|
{
|
||||||
|
if (s_is_booting.IsSet() || !s_hardware_initialized)
|
||||||
|
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();
|
||||||
|
|
|
@ -56,6 +56,7 @@ 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(bool wait_for_completion = false);
|
void SaveScreenShot(bool wait_for_completion = false);
|
||||||
void SaveScreenShot(std::string_view name, bool wait_for_completion = false);
|
void SaveScreenShot(std::string_view name, bool wait_for_completion = false);
|
||||||
|
|
Loading…
Reference in New Issue