diff --git a/Core/Config.cpp b/Core/Config.cpp index c7b194a3a35f..c563e48504ce 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -568,7 +568,7 @@ static int FastForwardModeFromString(const std::string &s) { return DefaultFastForwardMode(); } -std::string FastForwardModeToString(int v) { +static std::string FastForwardModeToString(int v) { switch (FastForwardMode(v)) { case FastForwardMode::CONTINUOUS: return "CONTINUOUS"; @@ -592,6 +592,7 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", CfgFlag::DEFAULT), #endif ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", CfgFlag::DEFAULT), + ConfigSetting("DisplayFramerateMode", &g_Config.iDisplayFramerateMode, 0, CfgFlag::DEFAULT), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, CfgFlag::DONT_SAVE), ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, false, CfgFlag::PER_GAME), ConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, CfgFlag::PER_GAME | CfgFlag::REPORT), diff --git a/Core/Config.h b/Core/Config.h index de2d6971cbfe..88d1e926a3dd 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -155,6 +155,7 @@ struct Config { std::string sD3D11Device; // Windows only std::string sCameraDevice; std::string sMicDevice; + int iDisplayFramerateMode; // enum DisplayFramerateMode. Android-only. bool bSoftwareRendering; bool bSoftwareRenderingJit; diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index bef7e082d0a9..f7f9457a2c29 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -168,3 +168,11 @@ enum class DebugOverlay : int { GPU_ALLOCATOR, FRAMEBUFFER_LIST, }; + +// Android-only for now +enum class DisplayFramerateMode : int { + DEFAULT, + REQUEST_60HZ, + FORCE_60HZ_METHOD1, + FORCE_60HZ_METHOD2, +}; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 1ea7935e7b2c..18be5cefc84e 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -598,6 +598,10 @@ void __DisplayFlip(int cyclesLate) { postEffectRequiresFlip = duplicateFrames || g_Config.bShaderChainRequires60FPS; } + if (!FrameTimingThrottled()) { + NOTICE_LOG(SYSTEM, "Throttle: %d %d", (int)fastForwardSkipFlip, (int)postEffectRequiresFlip); + } + const bool fbDirty = gpu->FramebufferDirty(); bool needFlip = fbDirty || noRecentFlip || postEffectRequiresFlip; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 6181a9f429ca..3387523448dd 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -716,6 +716,10 @@ void TouchTestScreen::axis(const AxisInput &axis) { void TouchTestScreen::DrawForeground(UIContext &dc) { Bounds bounds = dc.GetLayoutBounds(); + double now = time_now_d(); + double delta = now - lastFrameTime_; + lastFrameTime_ = now; + dc.BeginNoTex(); for (int i = 0; i < MAX_TOUCH_POINTS; i++) { if (touches_[i].id != -1) { @@ -747,19 +751,19 @@ void TouchTestScreen::DrawForeground(UIContext &dc) { #endif "dp_res: %dx%d pixel_res: %dx%d\n" "g_dpi: %0.3f g_dpi_scale: %0.3fx%0.3f\n" - "g_dpi_scale_real: %0.3fx%0.3f\n%s", + "g_dpi_scale_real: %0.3fx%0.3f\n" + "delta: %0.2f ms fps: %0.3f\n%s", #if PPSSPP_PLATFORM(ANDROID) System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES), #endif - g_display.dp_xres, g_display.dp_yres, - g_display.pixel_xres, g_display.pixel_yres, - g_display.dpi, - g_display.dpi_scale_x, g_display.dpi_scale_y, - g_display.dpi_scale_real_x, g_display.dpi_scale_real_y, extra_debug); + g_display.dp_xres, g_display.dp_yres, g_display.pixel_xres, g_display.pixel_yres, + g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, + g_display.dpi_scale_real_x, g_display.dpi_scale_real_y, + delta * 1000.0, 1.0 / delta, + extra_debug); // On Android, also add joystick debug data. - dc.DrawTextShadow(buffer, bounds.centerX(), bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); dc.Flush(); } diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index d096fdec531d..4402fbeb9827 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -169,6 +169,8 @@ class TouchTestScreen : public UIDialogScreenWithGameBackground { UI::TextView *lastKeyEvents_ = nullptr; + double lastFrameTime_ = 0.0; + void CreateViews() override; void UpdateLogView(); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 881d6ee8bc18..709edc94a227 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1731,6 +1731,19 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bGpuLogProfiler, dev->T("GPU log profiler"))); } +#if PPSSPP_PLATFORM(ANDROID) + static const char *framerateModes[] = { "Default", "Request 60Hz", "Force 60Hz 1", "Force 60Hz 2" }; + PopupMultiChoice *framerateMode = list->Add(new PopupMultiChoice(&g_Config.iDisplayFramerateMode, gr->T("Framerate mode"), framerateModes, 0, ARRAY_SIZE(framerateModes), I18NCat::GRAPHICS, screenManager())); + framerateMode->SetEnabledFunc([]() { return System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 30; }); + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) < 31) { + framerateMode->HideChoice(3); // not available + } + framerateMode->OnChoice.Add([this](UI::EventParams &e) { + System_Notify(SystemNotification::FORCE_RECREATE_ACTIVITY); + return UI::EVENT_DONE; + }); +#endif + static const char *ffModes[] = { "Render all frames", "", "Frame Skipping" }; PopupMultiChoice *ffMode = list->Add(new PopupMultiChoice(&g_Config.iFastForwardMode, dev->T("Fast-forward mode"), ffModes, 0, ARRAY_SIZE(ffModes), I18NCat::GRAPHICS, screenManager())); ffMode->SetEnabledFunc([]() { return !g_Config.bVSync; }); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index ba8aa1b6e9a3..ce0318bf20d0 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1464,6 +1464,10 @@ extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferHei return desiredBackbufferSizeY; } +extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDisplayFramerateMode(JNIEnv *, jclass) { + return g_Config.iDisplayFramerateMode; +} + std::vector System_GetCameraDeviceList() { jclass cameraClass = findClass("org/ppsspp/ppsspp/CameraHelper"); jmethodID deviceListMethod = getEnv()->GetStaticMethodID(cameraClass, "getDeviceList", "()Ljava/util/ArrayList;"); diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index cc0309af02a5..27a311e91c83 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -636,6 +636,7 @@ public void onCreate(Bundle savedInstanceState) { // mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8); // } } + mGLSurfaceView.setRenderer(nativeRenderer); setContentView(mGLSurfaceView); } else { @@ -661,6 +662,37 @@ public void onWindowFocusChanged(boolean hasFocus) { } } + private void applyFrameRate(Surface surface, float frameRateHz) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) + return; + if (mSurface != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + try { + int method = NativeApp.getDisplayFramerateMode(); + if (method > 0) { + Log.i(TAG, "Setting desired framerate to " + frameRateHz + " Hz method=" + method); + switch (method) { + case 1: + mSurface.setFrameRate(frameRateHz, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT); + break; + case 2: + mSurface.setFrameRate(frameRateHz, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + break; + case 3: + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + mSurface.setFrameRate(frameRateHz, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, Surface.CHANGE_FRAME_RATE_ALWAYS); + } + break; + default: + break; + } + + } + } catch (Exception e) { + Log.e(TAG, "Failed to set framerate: " + e.toString()); + } + } + } + public void notifySurface(Surface surface) { mSurface = surface; @@ -676,6 +708,8 @@ public void notifySurface(Surface surface) { } else { startRenderLoopThread(); } + } else if (mSurface != null) { + applyFrameRate(mSurface, 60.0f); } updateSustainedPerformanceMode(); } @@ -692,6 +726,8 @@ protected synchronized void startRenderLoopThread() { } Log.w(TAG, "startRenderLoopThread: Starting thread"); + + applyFrameRate(mSurface, 60.0f); runVulkanRenderLoop(mSurface); } diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java index 0e714be16909..c404cd3994bd 100644 --- a/android/src/org/ppsspp/ppsspp/NativeApp.java +++ b/android/src/org/ppsspp/ppsspp/NativeApp.java @@ -56,6 +56,7 @@ public class NativeApp { public static native String queryConfig(String queryName); public static native int getSelectedCamera(); + public static native int getDisplayFramerateMode(); public static native void setGpsDataAndroid(long time, float hdop, float latitude, float longitude, float altitude, float speed, float bearing); public static native void setSatInfoAndroid(short index, short id, short elevation, short azimuth, short snr, short good); public static native void pushCameraImageAndroid(byte[] image); diff --git a/android/src/org/ppsspp/ppsspp/NativeGLView.java b/android/src/org/ppsspp/ppsspp/NativeGLView.java index 372d697d8b46..8686ca7593c0 100644 --- a/android/src/org/ppsspp/ppsspp/NativeGLView.java +++ b/android/src/org/ppsspp/ppsspp/NativeGLView.java @@ -18,6 +18,8 @@ import android.os.Handler; import android.util.Log; import android.view.MotionEvent; +import android.view.Surface; +import android.view.SurfaceControl; import com.bda.controller.Controller; import com.bda.controller.ControllerListener; @@ -43,6 +45,7 @@ public NativeGLView(NativeActivity activity) { mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mController = Controller.getInstance(activity); + try { MogaHack.init(mController, activity); Log.i(TAG, "MOGA initialized"); diff --git a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java index 93e3471c18f7..a9a21d3b2a09 100644 --- a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java +++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java @@ -17,6 +17,8 @@ import android.util.Log; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.Surface; +import android.view.SurfaceControl; import android.view.SurfaceView; import com.bda.controller.Controller; @@ -45,8 +47,6 @@ public NativeSurfaceView(NativeActivity activity) { mController = Controller.getInstance(activity); - // this.getHolder().setFormat(PixelFormat.RGBA_8888); - try { MogaHack.init(mController, activity); Log.i(TAG, "MOGA initialized"); diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index f544174d0296..fc68e78d9f26 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -1,5 +1,6 @@ package org.ppsspp.ppsspp; +import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.Intent; import android.net.Uri; @@ -150,6 +151,7 @@ public String getDebugString(String str) { } } + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) public int openContentUri(String uriString, String mode) { try { Uri uri = Uri.parse(uriString); diff --git a/android/src/org/ppsspp/ppsspp/SizeManager.java b/android/src/org/ppsspp/ppsspp/SizeManager.java index af81f640ddc3..709447ff05a7 100644 --- a/android/src/org/ppsspp/ppsspp/SizeManager.java +++ b/android/src/org/ppsspp/ppsspp/SizeManager.java @@ -91,7 +91,11 @@ public void surfaceCreated(SurfaceHolder holder) { Log.i(TAG, "Bad orientation detected but ignored" + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? " (sdk version)" : "")); } - Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr); + Display display = activity.getWindowManager().getDefaultDisplay(); + + refreshRate = display.getRefreshRate(); + + Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr + " " + refreshRate + "Hz"); NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, refreshRate); getDesiredBackbufferSize(desiredSize);