mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
Android: Use Java thread for emulation thread
This commit is contained in:
parent
a5f9aa11e1
commit
5996945b37
|
@ -265,39 +265,20 @@ bool AndroidHostInterface::IsEmulationThreadPaused() const
|
||||||
return System::IsValid() && System::IsPaused();
|
return System::IsValid() && System::IsPaused();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidHostInterface::StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
|
||||||
SystemBootParameters boot_params, bool resume_state)
|
|
||||||
{
|
|
||||||
Assert(!IsEmulationThreadRunning());
|
|
||||||
|
|
||||||
emulation_activity = AndroidHelpers::GetJNIEnv()->NewGlobalRef(emulation_activity);
|
|
||||||
|
|
||||||
Log_DevPrintf("Starting emulation thread...");
|
|
||||||
m_emulation_thread_stop_request.store(false);
|
|
||||||
m_emulation_thread = std::thread(&AndroidHostInterface::EmulationThreadEntryPoint, this, emulation_activity,
|
|
||||||
initial_surface, std::move(boot_params), resume_state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidHostInterface::PauseEmulationThread(bool paused)
|
void AndroidHostInterface::PauseEmulationThread(bool paused)
|
||||||
{
|
{
|
||||||
Assert(IsEmulationThreadRunning());
|
Assert(IsEmulationThreadRunning());
|
||||||
RunOnEmulationThread([this, paused]() { PauseSystem(paused); });
|
RunOnEmulationThread([this, paused]() { PauseSystem(paused); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::StopEmulationThread()
|
void AndroidHostInterface::StopEmulationThreadLoop()
|
||||||
{
|
{
|
||||||
if (!IsEmulationThreadRunning())
|
if (!IsEmulationThreadRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log_InfoPrint("Stopping emulation thread...");
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
{
|
m_emulation_thread_stop_request.store(true);
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
m_sleep_cv.notify_one();
|
||||||
m_emulation_thread_stop_request.store(true);
|
|
||||||
m_sleep_cv.notify_one();
|
|
||||||
}
|
|
||||||
m_emulation_thread.join();
|
|
||||||
Log_InfoPrint("Emulation thread stopped");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function, bool blocking)
|
void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function, bool blocking)
|
||||||
|
@ -329,18 +310,19 @@ void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function,
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, jobject surface,
|
||||||
SystemBootParameters boot_params, bool resume_state)
|
SystemBootParameters boot_params, bool resume_state)
|
||||||
{
|
{
|
||||||
JNIEnv* thread_env;
|
ANativeWindow* native_surface = ANativeWindow_fromSurface(env, surface);
|
||||||
if (s_jvm->AttachCurrentThread(&thread_env, nullptr) != JNI_OK)
|
if (!native_surface)
|
||||||
{
|
{
|
||||||
ReportError("Failed to attach JNI to thread");
|
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
||||||
|
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateImGuiContext();
|
CreateImGuiContext();
|
||||||
m_surface = initial_surface;
|
m_surface = native_surface;
|
||||||
m_emulation_activity_object = emulation_activity;
|
m_emulation_activity_object = emulation_activity;
|
||||||
ApplySettings(true);
|
ApplySettings(true);
|
||||||
|
|
||||||
|
@ -358,35 +340,36 @@ void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity,
|
||||||
boot_result = BootSystem(boot_params);
|
boot_result = BootSystem(boot_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!boot_result)
|
if (boot_result)
|
||||||
|
{
|
||||||
|
// System is ready to go.
|
||||||
|
EmulationThreadLoop(env);
|
||||||
|
|
||||||
|
if (g_settings.save_state_on_exit)
|
||||||
|
SaveResumeSaveState();
|
||||||
|
|
||||||
|
PowerOffSystem();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ReportFormattedError("Failed to boot system on emulation thread (file:%s).", boot_params.filename.c_str());
|
ReportFormattedError("Failed to boot system on emulation thread (file:%s).", boot_params.filename.c_str());
|
||||||
DestroyImGuiContext();
|
|
||||||
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
|
||||||
thread_env->DeleteGlobalRef(m_emulation_activity_object);
|
|
||||||
m_emulation_activity_object = {};
|
|
||||||
s_jvm->DetachCurrentThread();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// System is ready to go.
|
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
||||||
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
|
|
||||||
EmulationThreadLoop();
|
|
||||||
|
|
||||||
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
|
||||||
|
|
||||||
if (g_settings.save_state_on_exit)
|
|
||||||
SaveResumeSaveState();
|
|
||||||
|
|
||||||
PowerOffSystem();
|
|
||||||
DestroyImGuiContext();
|
DestroyImGuiContext();
|
||||||
thread_env->DeleteGlobalRef(m_emulation_activity_object);
|
|
||||||
m_emulation_activity_object = {};
|
m_emulation_activity_object = {};
|
||||||
s_jvm->DetachCurrentThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::EmulationThreadLoop()
|
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);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// run any events
|
// run any events
|
||||||
|
@ -408,7 +391,11 @@ void AndroidHostInterface::EmulationThreadLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (System::IsPaused())
|
if (System::IsPaused())
|
||||||
{
|
{
|
||||||
|
@ -475,11 +462,12 @@ bool AndroidHostInterface::AcquireHostDisplay()
|
||||||
!display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
|
!display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
|
||||||
g_settings.gpu_threaded_presentation))
|
g_settings.gpu_threaded_presentation))
|
||||||
{
|
{
|
||||||
ReportError("Failed to acquire host display.");
|
|
||||||
display->DestroyRenderDevice();
|
display->DestroyRenderDevice();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The alignement was set prior to booting.
|
||||||
|
display->SetDisplayAlignment(m_display_alignment);
|
||||||
m_display = std::move(display);
|
m_display = std::move(display);
|
||||||
|
|
||||||
if (!CreateHostDisplayResources())
|
if (!CreateHostDisplayResources())
|
||||||
|
@ -591,6 +579,13 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidHostInterface::SetDisplayAlignment(HostDisplay::Alignment alignment)
|
||||||
|
{
|
||||||
|
m_display_alignment = alignment;
|
||||||
|
if (m_display)
|
||||||
|
m_display->SetDisplayAlignment(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::CreateImGuiContext()
|
void AndroidHostInterface::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
|
@ -956,28 +951,21 @@ DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isEmulationThreadRunning,
|
||||||
return AndroidHelpers::GetNativeClass(env, obj)->IsEmulationThreadRunning();
|
return AndroidHelpers::GetNativeClass(env, obj)->IsEmulationThreadRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_startEmulationThread, jobject obj, jobject emulationActivity,
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_runEmulationThread, jobject obj, jobject emulationActivity,
|
||||||
jobject surface, jstring filename, jboolean resume_state, jstring state_filename)
|
jobject surface, jstring filename, jboolean resume_state, jstring state_filename)
|
||||||
{
|
{
|
||||||
ANativeWindow* native_surface = ANativeWindow_fromSurface(env, surface);
|
|
||||||
if (!native_surface)
|
|
||||||
{
|
|
||||||
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string state_filename_str = AndroidHelpers::JStringToString(env, state_filename);
|
std::string state_filename_str = AndroidHelpers::JStringToString(env, state_filename);
|
||||||
|
|
||||||
SystemBootParameters boot_params;
|
SystemBootParameters boot_params;
|
||||||
boot_params.filename = AndroidHelpers::JStringToString(env, filename);
|
boot_params.filename = AndroidHelpers::JStringToString(env, filename);
|
||||||
|
|
||||||
return AndroidHelpers::GetNativeClass(env, obj)->StartEmulationThread(emulationActivity, native_surface,
|
AndroidHelpers::GetNativeClass(env, obj)->EmulationThreadEntryPoint(env, emulationActivity, surface,
|
||||||
std::move(boot_params), resume_state);
|
std::move(boot_params), resume_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThread, jobject obj)
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThreadLoop, jobject obj)
|
||||||
{
|
{
|
||||||
AndroidHelpers::GetNativeClass(env, obj)->StopEmulationThread();
|
AndroidHelpers::GetNativeClass(env, obj)->StopEmulationThreadLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width,
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width,
|
||||||
|
@ -1310,7 +1298,7 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setDisplayAlignment, jobject o
|
||||||
{
|
{
|
||||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
hi->RunOnEmulationThread(
|
hi->RunOnEmulationThread(
|
||||||
[hi, alignment]() { hi->GetDisplay()->SetDisplayAlignment(static_cast<HostDisplay::Alignment>(alignment)); });
|
[hi, alignment]() { hi->SetDisplayAlignment(static_cast<HostDisplay::Alignment>(alignment)); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_hasSurface, jobject obj)
|
DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_hasSurface, jobject obj)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "common/byte_stream.h"
|
#include "common/byte_stream.h"
|
||||||
#include "common/event.h"
|
#include "common/event.h"
|
||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
|
#include "core/host_display.h"
|
||||||
#include "frontend-common/common_host_interface.h"
|
#include "frontend-common/common_host_interface.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -38,15 +39,17 @@ public:
|
||||||
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
||||||
std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
|
std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
|
||||||
|
|
||||||
bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
|
bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); }
|
||||||
bool IsEmulationThreadPaused() const;
|
bool IsEmulationThreadPaused() const;
|
||||||
bool StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
|
||||||
SystemBootParameters boot_params, bool resume_state);
|
|
||||||
void RunOnEmulationThread(std::function<void()> function, bool blocking = false);
|
void RunOnEmulationThread(std::function<void()> function, bool blocking = false);
|
||||||
void PauseEmulationThread(bool paused);
|
void PauseEmulationThread(bool paused);
|
||||||
void StopEmulationThread();
|
void StopEmulationThreadLoop();
|
||||||
|
|
||||||
|
void EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, jobject initial_surface,
|
||||||
|
SystemBootParameters boot_params, bool resume_state);
|
||||||
|
|
||||||
void SurfaceChanged(ANativeWindow* surface, int format, int width, int height);
|
void SurfaceChanged(ANativeWindow* surface, int format, int width, int height);
|
||||||
|
void SetDisplayAlignment(HostDisplay::Alignment alignment);
|
||||||
|
|
||||||
void SetControllerType(u32 index, std::string_view type_name);
|
void SetControllerType(u32 index, std::string_view type_name);
|
||||||
void SetControllerButtonState(u32 index, s32 button_code, bool pressed);
|
void SetControllerButtonState(u32 index, s32 button_code, bool pressed);
|
||||||
|
@ -79,9 +82,7 @@ protected:
|
||||||
void OnRunningGameChanged() override;
|
void OnRunningGameChanged() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
void EmulationThreadLoop(JNIEnv* env);
|
||||||
SystemBootParameters boot_params, bool resume_state);
|
|
||||||
void EmulationThreadLoop();
|
|
||||||
|
|
||||||
void CreateImGuiContext();
|
void CreateImGuiContext();
|
||||||
void DestroyImGuiContext();
|
void DestroyImGuiContext();
|
||||||
|
@ -102,8 +103,10 @@ private:
|
||||||
std::deque<std::function<void()>> m_callback_queue;
|
std::deque<std::function<void()>> m_callback_queue;
|
||||||
std::atomic_bool m_callbacks_outstanding{false};
|
std::atomic_bool m_callbacks_outstanding{false};
|
||||||
|
|
||||||
std::thread m_emulation_thread;
|
|
||||||
std::atomic_bool m_emulation_thread_stop_request{false};
|
std::atomic_bool m_emulation_thread_stop_request{false};
|
||||||
|
std::atomic_bool m_emulation_thread_running{false};
|
||||||
|
|
||||||
|
HostDisplay::Alignment m_display_alignment = HostDisplay::Alignment::Center;
|
||||||
|
|
||||||
u64 m_last_vibration_update_time = 0;
|
u64 m_last_vibration_update_time = 0;
|
||||||
bool m_last_vibration_state = false;
|
bool m_last_vibration_state = false;
|
||||||
|
@ -111,11 +114,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace AndroidHelpers {
|
namespace AndroidHelpers {
|
||||||
|
|
||||||
JNIEnv* GetJNIEnv();
|
JNIEnv* GetJNIEnv();
|
||||||
AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj);
|
AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj);
|
||||||
std::string JStringToString(JNIEnv* env, jstring str);
|
std::string JStringToString(JNIEnv* env, jstring str);
|
||||||
std::unique_ptr<GrowableMemoryByteStream> ReadInputStreamToMemory(JNIEnv* env, jobject obj, u32 chunk_size = 65536);
|
std::unique_ptr<GrowableMemoryByteStream> ReadInputStreamToMemory(JNIEnv* env, jobject obj, u32 chunk_size = 65536);
|
||||||
jclass GetStringClass();
|
jclass GetStringClass();
|
||||||
|
|
||||||
} // namespace AndroidHelpers
|
} // namespace AndroidHelpers
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.Process;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -20,12 +21,6 @@ public class AndroidHostInterface {
|
||||||
private long mNativePointer;
|
private long mNativePointer;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
static public native String getScmVersion();
|
|
||||||
|
|
||||||
static public native String getFullScmVersion();
|
|
||||||
|
|
||||||
static public native AndroidHostInterface create(Context context, String userDirectory);
|
|
||||||
|
|
||||||
public AndroidHostInterface(Context context) {
|
public AndroidHostInterface(Context context) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
}
|
}
|
||||||
|
@ -46,15 +41,21 @@ public class AndroidHostInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public native String getScmVersion();
|
||||||
|
|
||||||
|
static public native String getFullScmVersion();
|
||||||
|
|
||||||
|
static public native AndroidHostInterface create(Context context, String userDirectory);
|
||||||
|
|
||||||
public native boolean isEmulationThreadRunning();
|
public native boolean isEmulationThreadRunning();
|
||||||
|
|
||||||
public native boolean startEmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String state_filename);
|
public native boolean runEmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String state_filename);
|
||||||
|
|
||||||
public native boolean isEmulationThreadPaused();
|
public native boolean isEmulationThreadPaused();
|
||||||
|
|
||||||
public native void pauseEmulationThread(boolean paused);
|
public native void pauseEmulationThread(boolean paused);
|
||||||
|
|
||||||
public native void stopEmulationThread();
|
public native void stopEmulationThreadLoop();
|
||||||
|
|
||||||
public native boolean hasSurface();
|
public native boolean hasSurface();
|
||||||
|
|
||||||
|
|
|
@ -108,12 +108,24 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EmulationThread mEmulationThread;
|
||||||
|
|
||||||
|
private void stopEmulationThread() {
|
||||||
|
if (mEmulationThread == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mEmulationThread.stopAndJoin();
|
||||||
|
mEmulationThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void onEmulationStarted() {
|
public void onEmulationStarted() {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
updateOrientation();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEmulationStopped() {
|
public void onEmulationStopped() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
AndroidHostInterface.getInstance().stopEmulationThread();
|
|
||||||
if (!mWasDestroyed && !mStopRequested)
|
if (!mWasDestroyed && !mStopRequested)
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
|
@ -159,7 +171,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
// Once we get a surface, we can boot.
|
// Once we get a surface, we can boot.
|
||||||
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
if (mEmulationThread != null) {
|
||||||
AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height);
|
AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height);
|
||||||
updateOrientation();
|
updateOrientation();
|
||||||
|
|
||||||
|
@ -175,9 +187,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
final boolean resumeState = getIntent().getBooleanExtra("resumeState", false);
|
final boolean resumeState = getIntent().getBooleanExtra("resumeState", false);
|
||||||
final String bootSaveStatePath = getIntent().getStringExtra("saveStatePath");
|
final String bootSaveStatePath = getIntent().getStringExtra("saveStatePath");
|
||||||
|
|
||||||
AndroidHostInterface.getInstance().startEmulationThread(this, holder.getSurface(), bootPath, resumeState, bootSaveStatePath);
|
mEmulationThread = EmulationThread.create(this, holder.getSurface(), bootPath, resumeState, bootSaveStatePath);
|
||||||
updateRequestedOrientation();
|
|
||||||
updateOrientation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -219,6 +229,10 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
}
|
}
|
||||||
mContentView.requestFocus();
|
mContentView.requestFocus();
|
||||||
|
|
||||||
|
// Sort out rotation.
|
||||||
|
updateRequestedOrientation();
|
||||||
|
updateOrientation();
|
||||||
|
|
||||||
// Hook up controller input.
|
// Hook up controller input.
|
||||||
updateControllers();
|
updateControllers();
|
||||||
registerInputDeviceListener();
|
registerInputDeviceListener();
|
||||||
|
@ -240,9 +254,9 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
Log.i("EmulationActivity", "OnStop");
|
Log.i("EmulationActivity", "OnStop");
|
||||||
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
if (mEmulationThread != null) {
|
||||||
mWasDestroyed = true;
|
mWasDestroyed = true;
|
||||||
AndroidHostInterface.getInstance().stopEmulationThread();
|
stopEmulationThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterInputDeviceListener();
|
unregisterInputDeviceListener();
|
||||||
|
@ -317,9 +331,6 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOrientation(int newOrientation) {
|
private void updateOrientation(int newOrientation) {
|
||||||
if (!AndroidHostInterface.getInstance().isEmulationThreadRunning())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (newOrientation == Configuration.ORIENTATION_PORTRAIT)
|
if (newOrientation == Configuration.ORIENTATION_PORTRAIT)
|
||||||
AndroidHostInterface.getInstance().setDisplayAlignment(AndroidHostInterface.DISPLAY_ALIGNMENT_TOP_OR_LEFT);
|
AndroidHostInterface.getInstance().setDisplayAlignment(AndroidHostInterface.DISPLAY_ALIGNMENT_TOP_OR_LEFT);
|
||||||
else
|
else
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
|
import android.os.Process;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Surface;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public class EmulationThread extends Thread {
|
||||||
|
private EmulationActivity emulationActivity;
|
||||||
|
private Surface surface;
|
||||||
|
private String filename;
|
||||||
|
private boolean resumeState;
|
||||||
|
private String stateFilename;
|
||||||
|
|
||||||
|
private EmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String stateFilename) {
|
||||||
|
super("EmulationThread");
|
||||||
|
this.emulationActivity = emulationActivity;
|
||||||
|
this.surface = surface;
|
||||||
|
this.filename = filename;
|
||||||
|
this.resumeState = resumeState;
|
||||||
|
this.stateFilename = stateFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EmulationThread create(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String stateFilename) {
|
||||||
|
Log.i("EmulationThread", String.format("Starting emulation thread (%s)...", filename));
|
||||||
|
|
||||||
|
EmulationThread thread = new EmulationThread(emulationActivity, surface, filename, resumeState, stateFilename);
|
||||||
|
thread.start();
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.i("EmulationThread", "Failed to set priority for emulation thread: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidHostInterface.getInstance().runEmulationThread(emulationActivity, surface, filename, resumeState, stateFilename);
|
||||||
|
Log.i("EmulationThread", "Emulation thread exiting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopAndJoin() {
|
||||||
|
AndroidHostInterface.getInstance().stopEmulationThreadLoop();
|
||||||
|
try {
|
||||||
|
join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.i("EmulationThread", "join() interrupted: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue