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

View File

@ -1,6 +1,7 @@
package com.limelight.binding.video; package com.limelight.binding.video;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import org.jcodec.codecs.h264.H264Utils; import org.jcodec.codecs.h264.H264Utils;
@ -123,8 +124,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
this.crashListener = crashListener; this.crashListener = crashListener;
this.consecutiveCrashCount = consecutiveCrashCount; this.consecutiveCrashCount = consecutiveCrashCount;
// Disable spinner threads in battery saver mode // Disable spinner threads in battery saver mode or 4K
if (prefs.batterySaver) { if (prefs.batterySaver || prefs.height >= 2160) {
spinnerThreads = new Thread[0]; spinnerThreads = new Thread[0];
} }
else { else {
@ -193,6 +194,17 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return false; 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() { public int getActiveVideoFormat() {
return this.videoFormat; return this.videoFormat;
} }
@ -424,26 +436,70 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
rendererThread.start(); 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() { private void startSpinnerThreads() {
LimeLog.info("Using "+spinnerThreads.length+" spinner threads"); LimeLog.info("Using "+spinnerThreads.length+" spinner threads");
for (int i = 0; i < spinnerThreads.length; i++) { for (int i = 0; i < spinnerThreads.length; i++) {
spinnerThreads[i] = new Thread() { if (spinnerThreads[i] != null) {
@Override continue;
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. startSpinnerThread(i);
while (!stopping) { }
try { }
Thread.sleep(0, 1);
} catch (InterruptedException e) { private Thread[] signalSpinnerStop() {
break; // 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].setName("Spinner-"+i); spinnerThreads[i] = null;
spinnerThreads[i].setPriority(Thread.MIN_PRIORITY); }
spinnerThreads[i].start();
// 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 // Halt the spinner threads
for (Thread t : spinnerThreads) { stopSpinnerThreads();
t.interrupt();
}
for (Thread t : spinnerThreads) {
try {
t.join();
} catch (InterruptedException ignored) { }
}
} }
@Override @Override