Android: Decouple SurfaceView initialization and emulation start.

This commit is contained in:
Eder Bastos 2015-05-24 12:04:32 -04:00
parent ad9dae30a8
commit 4faff3cf62
3 changed files with 127 additions and 8 deletions

View File

@ -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);
}
};
} }

View File

@ -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"

View File

@ -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);