Add Performance Statistics to EmulationActivity

This commit adds performance statistics to the emulator that can be toggled in preferences. The layout of `EmulationActivity` was also changed from `ConstraintLayout` to `RelativeLayout` due to poor performance of the former.
This commit is contained in:
◱ PixelyIon 2020-04-18 05:46:09 +05:30 committed by ◱ PixelyIon
parent fb1a158e8f
commit 7f78a679c3
8 changed files with 86 additions and 29 deletions

View File

@ -11,6 +11,8 @@ bool Halt;
jobject Surface;
uint FaultCount;
skyline::GroupMutex JniMtx;
skyline::u16 fps;
skyline::u32 frametime;
void signalHandler(int signal) {
syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal));
@ -74,3 +76,11 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *
Surface = surface;
JniMtx.unlock();
}
extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *env, jobject thiz) {
return fps;
}
extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *env, jobject thiz) {
return static_cast<float>(frametime) / 100;
}

View File

@ -8,6 +8,8 @@
extern bool Halt;
extern jobject Surface;
extern skyline::u16 fps;
extern skyline::u32 frametime;
namespace skyline::gpu {
GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) {
@ -57,12 +59,16 @@ namespace skyline::gpu {
vsyncEvent->Signal();
texture->releaseCallback();
if (prevTime != 0) {
auto now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
state.logger->Error("{} ms, {} FPS", (now - prevTime) / 1000, 1000000 / (now - prevTime));
}
if (frameTimestamp) {
auto now = util::GetTimeNs();
prevTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
frametime = static_cast<u32>((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals
fps = static_cast<u16>(1000000000 / (now - frameTimestamp));
frameTimestamp = now;
} else {
frameTimestamp = util::GetTimeNs();
}
}
}
}

View File

@ -20,7 +20,7 @@ namespace skyline::gpu {
ANativeWindow *window; //!< The ANativeWindow to render to
const DeviceState &state; //!< The state of the device
bool surfaceUpdate{}; //!< If the surface needs to be updated
double prevTime{}; //!< The time passed from the last frame
u64 frameTimestamp{}; //!< The timestamp of the last frame being shown
public:
std::queue<std::shared_ptr<PresentationTexture>> presentationQueue; //!< A queue of all the PresentationTextures to be posted to the display

View File

@ -14,8 +14,9 @@ import android.view.Surface
import android.view.SurfaceHolder
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import emu.skyline.loader.getRomFormat
import kotlinx.android.synthetic.main.app_activity.*
import kotlinx.android.synthetic.main.emu_activity.*
import java.io.File
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
@ -78,6 +79,16 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
*/
private external fun setSurface(surface: Surface?)
/**
* This returns the current FPS of the application
*/
private external fun getFps(): Int
/**
* This returns the current frame-time of the application
*/
private external fun getFrametime(): Float
/**
* This executes the specified ROM, [preferenceFd] and [logFd] are assumed to be valid beforehand
*
@ -101,12 +112,14 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
}
/**
* This sets up [preferenceFd] and [logFd] then calls [executeApplication] for executing the application
* This makes the window fullscreen then sets up [preferenceFd] and [logFd], sets up the performance statistics and finally calls [executeApplication] for executing the application
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.app_activity)
setContentView(R.layout.emu_activity)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
val preference = File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml")
preferenceFd = ParcelFileDescriptor.open(preference, ParcelFileDescriptor.MODE_READ_WRITE)
@ -114,9 +127,21 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
val log = File("${applicationInfo.dataDir}/skyline.log")
logFd = ParcelFileDescriptor.open(log, ParcelFileDescriptor.MODE_CREATE or ParcelFileDescriptor.MODE_READ_WRITE)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
game_view.holder.addCallback(this)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
if (sharedPreferences.getBoolean("perf_stats", false)) {
lateinit var perfRunnable: Runnable
perfRunnable = Runnable {
perf_stats.text = "${getFps()} FPS\n${getFrametime()}ms"
perf_stats.postDelayed(perfRunnable, 250)
}
perf_stats.postDelayed(perfRunnable, 250)
}
executeApplication(intent.data!!)
}

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".EmulationActivity">
<SurfaceView
android:id="@+id/game_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".EmulationActivity">
<SurfaceView
android:id="@+id/game_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/perf_stats"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:textColor="#5fffffff" />
</RelativeLayout>

View File

@ -32,7 +32,7 @@
<string name="log_level">Log Level</string>
<string name="log_compact">Compact Logs</string>
<string name="log_compact_desc_on">Logs will be displayed in a compact form factor</string>
<string name="log_compact_desc_off">The logs will be displayed in a verbose form factor</string>
<string name="log_compact_desc_off">Logs will be displayed in a verbose form factor</string>
<string name="system">System</string>
<string name="use_docked">Use Docked Mode</string>
<string name="handheld_enabled">The system will emulate being in handheld mode</string>
@ -59,4 +59,7 @@
<string name="ktstd_description">We use Kotlin Standard Library for accessing convenience functions in Kotlin (Apache License 2.0)</string>
<string name="mtico">Material Design Icons</string>
<string name="mtico_description">We use Material Design Icons to have consistent iconography throughout the application</string>
<string name="perf_stats">Show Performance Statistics</string>
<string name="perf_stats_desc_off">Performance Statistics will not be shown</string>
<string name="perf_stats_desc_on">Performance Statistics will be shown in the top-left corner</string>
</resources>

View File

@ -43,6 +43,12 @@
android:summaryOn="@string/select_action_desc_on"
app:key="select_action"
app:title="@string/select_action" />
<CheckBoxPreference
android:defaultValue="false"
android:summaryOff="@string/perf_stats_desc_off"
android:summaryOn="@string/perf_stats_desc_on"
app:key="perf_stats"
app:title="@string/perf_stats" />
<ListPreference
android:defaultValue="2"
android:entries="@array/log_level"