Android: Decouple SurfaceView initialization and emulation start.
This commit is contained in:
parent
ad9dae30a8
commit
4faff3cf62
|
@ -4,7 +4,11 @@ import android.app.Fragment;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
@ -14,7 +18,7 @@ import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.emulation.overlay.InputOverlay;
|
import org.dolphinemu.dolphinemu.emulation.overlay.InputOverlay;
|
||||||
|
|
||||||
|
|
||||||
public final class EmulationFragment extends Fragment
|
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
||||||
{
|
{
|
||||||
public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".emulation_fragment";
|
public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".emulation_fragment";
|
||||||
|
|
||||||
|
@ -22,8 +26,19 @@ public final class EmulationFragment extends Fragment
|
||||||
|
|
||||||
private SharedPreferences mPreferences;
|
private SharedPreferences mPreferences;
|
||||||
|
|
||||||
|
private SurfaceView mSurfaceView;
|
||||||
|
private Surface mSurface;
|
||||||
|
|
||||||
private InputOverlay mInputOverlay;
|
private InputOverlay mInputOverlay;
|
||||||
|
|
||||||
|
private Thread mEmulationThread;
|
||||||
|
|
||||||
|
private String mPath;
|
||||||
|
|
||||||
|
private boolean mEmulationStarted;
|
||||||
|
private boolean mEmulationRunning;
|
||||||
|
|
||||||
|
|
||||||
public static EmulationFragment newInstance(String path)
|
public static EmulationFragment newInstance(String path)
|
||||||
{
|
{
|
||||||
EmulationFragment fragment = new EmulationFragment();
|
EmulationFragment fragment = new EmulationFragment();
|
||||||
|
@ -43,6 +58,9 @@ public final class EmulationFragment extends Fragment
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
|
setRetainInstance(true);
|
||||||
|
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +70,15 @@ public final class EmulationFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
String path = getArguments().getString(ARGUMENT_GAME_PATH);
|
mPath = getArguments().getString(ARGUMENT_GAME_PATH);
|
||||||
|
NativeLibrary.SetFilename(mPath);
|
||||||
|
|
||||||
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
||||||
|
|
||||||
|
mSurfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation);
|
||||||
mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay);
|
mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay);
|
||||||
|
|
||||||
NativeLibrary.SetFilename(path);
|
mSurfaceView.getHolder().addCallback(this);
|
||||||
|
|
||||||
|
|
||||||
// If the input overlay was previously disabled, then don't show it.
|
// If the input overlay was previously disabled, then don't show it.
|
||||||
if (!mPreferences.getBoolean("showInputOverlay", true))
|
if (!mPreferences.getBoolean("showInputOverlay", true))
|
||||||
|
@ -67,6 +86,18 @@ public final class EmulationFragment extends Fragment
|
||||||
mInputOverlay.setVisibility(View.GONE);
|
mInputOverlay.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (savedInstanceState == null)
|
||||||
|
{
|
||||||
|
mEmulationThread = new Thread(mEmulationRunner);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Likely a rotation occurred.
|
||||||
|
// TODO Pass native code the Surface, which will have been recreated, from surfaceChanged()
|
||||||
|
// TODO Also, write the native code that will get the video backend to accept the new Surface as one of its own.
|
||||||
|
}
|
||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,22 +105,25 @@ public final class EmulationFragment extends Fragment
|
||||||
public void onStart()
|
public void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
NativeLibrary.UnPauseEmulation();
|
startEmulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop()
|
public void onStop()
|
||||||
{
|
{
|
||||||
super.onStop();
|
super.onStop();
|
||||||
NativeLibrary.PauseEmulation();
|
pauseEmulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView()
|
public void onDestroyView()
|
||||||
{
|
{
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
if (getActivity().isFinishing())
|
||||||
|
{
|
||||||
NativeLibrary.StopEmulation();
|
NativeLibrary.StopEmulation();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void toggleInputOverlayVisibility()
|
public void toggleInputOverlayVisibility()
|
||||||
{
|
{
|
||||||
|
@ -111,4 +145,78 @@ public final class EmulationFragment extends Fragment
|
||||||
|
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(SurfaceHolder holder)
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Surface created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Surface changed. Resolution: " + width + "x" + height);
|
||||||
|
mSurface = holder.getSurface();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder)
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Surface destroyed.");
|
||||||
|
|
||||||
|
if (mEmulationRunning)
|
||||||
|
{
|
||||||
|
pauseEmulation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startEmulation()
|
||||||
|
{
|
||||||
|
if (!mEmulationStarted)
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Starting emulation thread.");
|
||||||
|
|
||||||
|
mEmulationThread.start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Resuming emulation.");
|
||||||
|
NativeLibrary.UnPauseEmulation();
|
||||||
|
}
|
||||||
|
|
||||||
|
mEmulationRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pauseEmulation()
|
||||||
|
{
|
||||||
|
Log.d("DolphinEmu", "Pausing emulation.");
|
||||||
|
|
||||||
|
NativeLibrary.PauseEmulation();
|
||||||
|
mEmulationRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable mEmulationRunner = new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mEmulationRunning = true;
|
||||||
|
mEmulationStarted = true;
|
||||||
|
|
||||||
|
// Loop until onSurfaceCreated succeeds
|
||||||
|
while (mSurface == null)
|
||||||
|
{
|
||||||
|
if (!mEmulationRunning)
|
||||||
|
{
|
||||||
|
// So that if the user quits before this gets a surface, we don't loop infinitely.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i("DolphinEmu", "Starting emulation: " + mSurface);
|
||||||
|
|
||||||
|
// Start emulation using the provided Surface.
|
||||||
|
NativeLibrary.Run(mSurface);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment">
|
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment">
|
||||||
|
|
||||||
<!-- This is what everything is rendered to during emulation -->
|
<!-- This is what everything is rendered to during emulation -->
|
||||||
<org.dolphinemu.dolphinemu.emulation.NativeGLSurfaceView
|
<SurfaceView
|
||||||
android:id="@+id/surface_emulation"
|
android:id="@+id/surface_emulation"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -561,8 +561,16 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDi
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf)
|
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf)
|
||||||
{
|
{
|
||||||
|
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", g_filename.c_str());
|
||||||
|
|
||||||
surf = ANativeWindow_fromSurface(env, _surf);
|
surf = ANativeWindow_fromSurface(env, _surf);
|
||||||
|
|
||||||
|
if (surf == nullptr)
|
||||||
|
{
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Install our callbacks
|
// Install our callbacks
|
||||||
OSD::AddCallback(OSD::OSD_INIT, ButtonManager::Init);
|
OSD::AddCallback(OSD::OSD_INIT, ButtonManager::Init);
|
||||||
OSD::AddCallback(OSD::OSD_SHUTDOWN, ButtonManager::Shutdown);
|
OSD::AddCallback(OSD::OSD_SHUTDOWN, ButtonManager::Shutdown);
|
||||||
|
@ -574,8 +582,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *
|
||||||
|
|
||||||
// No use running the loop when booting fails
|
// No use running the loop when booting fails
|
||||||
if ( BootManager::BootCore( g_filename.c_str() ) )
|
if ( BootManager::BootCore( g_filename.c_str() ) )
|
||||||
|
{
|
||||||
|
PowerPC::Start();
|
||||||
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
|
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
|
||||||
updateMainFrameEvent.Wait();
|
updateMainFrameEvent.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
UICommon::Shutdown();
|
UICommon::Shutdown();
|
||||||
ANativeWindow_release(surf);
|
ANativeWindow_release(surf);
|
||||||
|
|
Loading…
Reference in New Issue