Disable performance optimizations when in multi-window

This commit is contained in:
Cameron Gutman 2017-11-18 17:14:40 -08:00
parent 4deb881ec8
commit 912925ef2c
2 changed files with 88 additions and 27 deletions

View File

@ -29,6 +29,7 @@ import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.PictureInPictureParams;
import android.app.Service;
@ -517,16 +518,27 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
@Override
@TargetApi(Build.VERSION_CODES.N)
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
// In multi-window, we don't want to use the full-screen layout
// flag. It will cause us to collide with the system UI.
// This function will also be called for PiP so we can cover
// that case here too.
if (isInMultiWindowMode) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Disable performance optimizations for foreground
getWindow().setSustainedPerformanceMode(false);
decoderRenderer.notifyVideoBackground();
}
else {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Enable performance optimizations for foreground
getWindow().setSustainedPerformanceMode(true);
decoderRenderer.notifyVideoForeground();
}
// Correct the system UI visibility flags

View File

@ -1,6 +1,7 @@
package com.limelight.binding.video;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale;
import org.jcodec.codecs.h264.H264Utils;
@ -123,8 +124,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
this.crashListener = crashListener;
this.consecutiveCrashCount = consecutiveCrashCount;
// Disable spinner threads in battery saver mode
if (prefs.batterySaver) {
// Disable spinner threads in battery saver mode or 4K
if (prefs.batterySaver || prefs.height >= 2160) {
spinnerThreads = new Thread[0];
}
else {
@ -193,6 +194,17 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return false;
}
public void notifyVideoForeground() {
startSpinnerThreads();
}
public void notifyVideoBackground() {
// Signal the spinner threads to stop but
// don't wait for them to terminate to avoid
// delaying the state transition
signalSpinnerStop();
}
public int getActiveVideoFormat() {
return this.videoFormat;
}
@ -424,26 +436,70 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
rendererThread.start();
}
private void startSpinnerThread(final int i) {
spinnerThreads[i] = new Thread() {
@Override
public void run() {
// This thread exists to keep the CPU at a higher DVFS state on devices
// where the governor scales clock speed sporadically, causing dropped frames.
//
// Run until we notice our thread has been removed from the spinner threads
// array. Even if we don't notice immediately, we'll notice soon enough.
// This will also ensure we terminate even if someone has restarted spinning
// before we realized we should stop.
while (this == spinnerThreads[i]) {
try {
Thread.sleep(0, 1);
} catch (InterruptedException e) {
break;
}
}
}
};
spinnerThreads[i].setName("Spinner-"+i);
spinnerThreads[i].setPriority(Thread.MIN_PRIORITY);
spinnerThreads[i].start();
}
private void startSpinnerThreads() {
LimeLog.info("Using "+spinnerThreads.length+" spinner threads");
for (int i = 0; i < spinnerThreads.length; i++) {
spinnerThreads[i] = new Thread() {
@Override
public void run() {
// This thread exists to keep the CPU at a higher DVFS state on devices
// where the governor scales clock speed sporadically, causing dropped frames.
while (!stopping) {
try {
Thread.sleep(0, 1);
} catch (InterruptedException e) {
break;
}
}
}
};
spinnerThreads[i].setName("Spinner-"+i);
spinnerThreads[i].setPriority(Thread.MIN_PRIORITY);
spinnerThreads[i].start();
if (spinnerThreads[i] != null) {
continue;
}
startSpinnerThread(i);
}
}
private Thread[] signalSpinnerStop() {
// Capture current running threads
Thread[] runningThreads = Arrays.copyOf(spinnerThreads, spinnerThreads.length);
// Clear the spinner threads to signal their termination
for (int i = 0; i < spinnerThreads.length; i++) {
spinnerThreads[i] = null;
}
// Interrupt the threads
for (int i = 0; i < runningThreads.length; i++) {
if (runningThreads[i] != null) {
runningThreads[i].interrupt();
}
}
return runningThreads;
}
private void stopSpinnerThreads() {
// Signal and wait for the threads to stop
Thread[] runningThreads = signalSpinnerStop();
for (int i = 0; i < runningThreads.length; i++) {
if (runningThreads[i] != null) {
try {
runningThreads[i].join();
} catch (InterruptedException ignored) { }
}
}
}
@ -517,14 +573,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
// Halt the spinner threads
for (Thread t : spinnerThreads) {
t.interrupt();
}
for (Thread t : spinnerThreads) {
try {
t.join();
} catch (InterruptedException ignored) { }
}
stopSpinnerThreads();
}
@Override