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.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
@ -14,7 +18,7 @@ import org.dolphinemu.dolphinemu.R;
|
|||
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";
|
||||
|
||||
|
@ -22,8 +26,19 @@ public final class EmulationFragment extends Fragment
|
|||
|
||||
private SharedPreferences mPreferences;
|
||||
|
||||
private SurfaceView mSurfaceView;
|
||||
private Surface mSurface;
|
||||
|
||||
private InputOverlay mInputOverlay;
|
||||
|
||||
private Thread mEmulationThread;
|
||||
|
||||
private String mPath;
|
||||
|
||||
private boolean mEmulationStarted;
|
||||
private boolean mEmulationRunning;
|
||||
|
||||
|
||||
public static EmulationFragment newInstance(String path)
|
||||
{
|
||||
EmulationFragment fragment = new EmulationFragment();
|
||||
|
@ -43,6 +58,9 @@ public final class EmulationFragment extends Fragment
|
|||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||
setRetainInstance(true);
|
||||
|
||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
}
|
||||
|
||||
|
@ -52,14 +70,15 @@ public final class EmulationFragment extends Fragment
|
|||
@Override
|
||||
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);
|
||||
|
||||
mSurfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation);
|
||||
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 (!mPreferences.getBoolean("showInputOverlay", true))
|
||||
|
@ -67,6 +86,18 @@ public final class EmulationFragment extends Fragment
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -74,21 +105,24 @@ public final class EmulationFragment extends Fragment
|
|||
public void onStart()
|
||||
{
|
||||
super.onStart();
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
startEmulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
{
|
||||
super.onStop();
|
||||
NativeLibrary.PauseEmulation();
|
||||
pauseEmulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView()
|
||||
{
|
||||
super.onDestroyView();
|
||||
NativeLibrary.StopEmulation();
|
||||
if (getActivity().isFinishing())
|
||||
{
|
||||
NativeLibrary.StopEmulation();
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleInputOverlayVisibility()
|
||||
|
@ -111,4 +145,78 @@ public final class EmulationFragment extends Fragment
|
|||
|
||||
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">
|
||||
|
||||
<!-- This is what everything is rendered to during emulation -->
|
||||
<org.dolphinemu.dolphinemu.emulation.NativeGLSurfaceView
|
||||
<SurfaceView
|
||||
android:id="@+id/surface_emulation"
|
||||
android:layout_height="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)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", g_filename.c_str());
|
||||
|
||||
surf = ANativeWindow_fromSurface(env, _surf);
|
||||
|
||||
if (surf == nullptr)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Install our callbacks
|
||||
OSD::AddCallback(OSD::OSD_INIT, ButtonManager::Init);
|
||||
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
|
||||
if ( BootManager::BootCore( g_filename.c_str() ) )
|
||||
{
|
||||
PowerPC::Start();
|
||||
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
|
||||
updateMainFrameEvent.Wait();
|
||||
}
|
||||
|
||||
UICommon::Shutdown();
|
||||
ANativeWindow_release(surf);
|
||||
|
|
Loading…
Reference in New Issue