From 97d0a8f0ffba1c94d58156acc499478a735fce9c Mon Sep 17 00:00:00 2001 From: zhang wei Date: Mon, 1 Jun 2020 02:47:22 +0800 Subject: [PATCH] Presenting in ui thread (#92) * present in ui thread * rm test file * use gradle 3.6.3 * fx present issue --- .../citra_emu/ExampleInstrumentedTest.java | 26 ----------- .../org/citra/citra_emu/NativeLibrary.java | 2 + .../fragments/EmulationFragment.java | 17 +++++-- .../src/main/jni/emu_window/emu_window.cpp | 46 +++++++------------ .../app/src/main/jni/emu_window/emu_window.h | 13 +++--- src/android/app/src/main/jni/native.cpp | 12 +++-- .../org/citra/citra_emu/ExampleUnitTest.java | 17 ------- src/android/build.gradle | 2 +- 8 files changed, 50 insertions(+), 85 deletions(-) delete mode 100644 src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java delete mode 100644 src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java diff --git a/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java b/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java deleted file mode 100644 index 671fb4b30..000000000 --- a/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.citra.citra_emu; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("org.citra.citra_emu", appContext.getPackageName()); - } -} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.java b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.java index 464336592..9baeeb5e4 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.java @@ -172,6 +172,8 @@ public final class NativeLibrary { public static native void SurfaceDestroyed(); + public static native void DoFrame(); + /** * Unpauses emulation from a paused state. */ diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.java b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.java index 1057e4c16..445faa047 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.java @@ -6,6 +6,7 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; +import android.view.Choreographer; import android.view.LayoutInflater; import android.view.Surface; import android.view.SurfaceHolder; @@ -30,7 +31,7 @@ import org.citra.citra_emu.utils.DirectoryStateReceiver; import org.citra.citra_emu.utils.EmulationMenuSettings; import org.citra.citra_emu.utils.Log; -public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback { +public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback, Choreographer.FrameCallback { private static final String KEY_GAMEPATH = "gamepath"; private static final Handler perfStatsUpdateHandler = new Handler(); @@ -114,6 +115,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C @Override public void onResume() { super.onResume(); + Choreographer.getInstance().postFrameCallback(this); if (DirectoryInitialization.areCitraDirectoriesReady()) { mEmulationState.run(activity.isActivityRecreated()); } else { @@ -128,8 +130,11 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C directoryStateReceiver = null; } - if (mEmulationState.isRunning()) + if (mEmulationState.isRunning()) { mEmulationState.pause(); + } + + Choreographer.getInstance().removeFrameCallback(this); super.onPause(); } @@ -227,6 +232,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mEmulationState.clearSurface(); } + @Override + public void doFrame(long frameTimeNanos) { + Choreographer.getInstance().postFrameCallback(this); + NativeLibrary.DoFrame(); + } + public void stopEmulation() { mEmulationState.stop(); } @@ -342,9 +353,9 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C private void runWithValidSurface() { mRunWhenSurfaceIsValid = false; if (state == State.STOPPED) { + NativeLibrary.SurfaceChanged(mSurface); Thread mEmulationThread = new Thread(() -> { - NativeLibrary.SurfaceChanged(mSurface); Log.debug("[EmulationFragment] Starting emulation thread."); NativeLibrary.Run(mGamePath); }, "NativeEmulation"); diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 9ba9605ac..068018b69 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -79,6 +79,7 @@ static void UpdateLandscapeScreenLayout() { void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { render_window = surface; + StopPresenting(); } bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) { @@ -219,7 +220,6 @@ void EmuWindow_Android::DestroyContext() { } EmuWindow_Android::~EmuWindow_Android() { - StopPresenting(); DestroyWindowSurface(); DestroyContext(); } @@ -228,34 +228,26 @@ std::unique_ptr EmuWindow_Android::CreateSharedContex return std::make_unique(egl_display, egl_config, egl_context); } -void EmuWindow_Android::StartPresenting() { - ASSERT(!presentation_thread); - is_presenting = true; - presentation_thread = - std::make_unique([emu_window{this}] { emu_window->Present(); }); -} - void EmuWindow_Android::StopPresenting() { - is_presenting = false; - if (presentation_thread) { - presentation_thread->join(); - presentation_thread.reset(); + if (presenting_state == PresentingState::Running) { + eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } + presenting_state = PresentingState::Stopped; } -bool EmuWindow_Android::IsPresenting() const { - return is_presenting; -} - -void EmuWindow_Android::Present() { - eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +void EmuWindow_Android::TryPresenting() { + if (presenting_state != PresentingState::Running) { + if (presenting_state == PresentingState::Initial) { + eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + presenting_state = PresentingState::Running; + } else { + return; + } + } eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0); - while (IsPresenting()) { - VideoCore::g_renderer->TryPresent(100); - eglSwapBuffers(egl_display, egl_surface); - } - eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + VideoCore::g_renderer->TryPresent(100); + eglSwapBuffers(egl_display, egl_surface); } void EmuWindow_Android::PollEvents() { @@ -266,14 +258,10 @@ void EmuWindow_Android::PollEvents() { host_window = render_window; render_window = nullptr; - if (IsPresenting()) { - StopPresenting(); - } - DestroyWindowSurface(); CreateWindowSurface(); OnFramebufferSizeChanged(); - StartPresenting(); + presenting_state = PresentingState::Initial; } void EmuWindow_Android::MakeCurrent() { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index f27b462ff..10a293c96 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include @@ -51,9 +50,8 @@ public: void MakeCurrent() override; void DoneCurrent() override; - void StartPresenting(); + void TryPresenting(); void StopPresenting(); - bool IsPresenting() const; std::unique_ptr CreateSharedContext() const override; @@ -76,7 +74,10 @@ private: std::unique_ptr core_context; - std::unique_ptr presentation_thread; - - bool is_presenting{}; + enum class PresentingState { + Initial, + Running, + Stopped, + }; + PresentingState presenting_state{}; }; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 04b7f774e..06a7fbbb3 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -102,7 +102,6 @@ static void TryShutdown() { return; } - window->StopPresenting(); window->DoneCurrent(); Core::System::GetInstance().Shutdown(); window.reset(); @@ -167,8 +166,6 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { is_running = true; pause_emulation = false; - window->StartPresenting(); - SCOPE_EXIT({ TryShutdown(); }); // Audio stretching on Android is only useful with lower framerates, disable it when fullspeed @@ -196,6 +193,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { std::unique_lock pause_lock(paused_mutex); running_cv.wait(pause_lock, [] { return !pause_emulation || !is_running; }); + window->PollEvents(); } } @@ -225,6 +223,13 @@ void Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, } } +void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) { + if (!is_running || pause_emulation) { + return; + } + window->TryPresenting(); +} + void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env, [[maybe_unused]] jclass clazz, jint layout_option, @@ -302,6 +307,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_StopEmulation(JNIEnv* env, [[maybe_unused]] jclass clazz) { is_running = false; pause_emulation = false; + window->StopPresenting(); running_cv.notify_all(); } diff --git a/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java b/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java deleted file mode 100644 index 4e4bb317f..000000000 --- a/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.citra.citra_emu; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/src/android/build.gradle b/src/android/build.gradle index 6f6ecaf8e..92b0e7081 100644 --- a/src/android/build.gradle +++ b/src/android/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.1' + classpath 'com.android.tools.build:gradle:3.6.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files