Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bcd2ee068 | |||
| d4ff58b3ad | |||
| c797318ece | |||
| 82387d23f8 | |||
| 766e629be5 | |||
| b93aa42c0c |
+34
-2
@@ -11,8 +11,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
|
||||
versionName "5.6.4"
|
||||
versionCode = 143
|
||||
versionName "5.6.5"
|
||||
versionCode = 145
|
||||
}
|
||||
|
||||
flavorDimensions "root"
|
||||
@@ -54,6 +54,38 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
// To whomever is releasing/using an APK in release mode with
|
||||
// Moonlight's official application ID, please stop. I see every
|
||||
// single one of your crashes in my Play Console and it makes
|
||||
// Moonlight's reliability look worse and makes it more difficult
|
||||
// to distinguish real crashes from your crashy VR app. Seriously,
|
||||
// 44 of the *same* native crash in 72 hours and a few each of
|
||||
// several other crashes.
|
||||
//
|
||||
// This is technically not your fault. I would have hoped Google
|
||||
// would validate the signature of the APK before attributing
|
||||
// the crash to it. I asked their Play Store support about this
|
||||
// and they said they don't and don't have plans to, so that sucks.
|
||||
//
|
||||
// In any case, it's bad form to release an APK using someone
|
||||
// else's application ID. There is no legitimate reason, that
|
||||
// anyone would need to comment out the following line, except me
|
||||
// when I release an official signed Moonlight build. If you feel
|
||||
// like doing so would solve something, I can tell you it will not.
|
||||
// You can't upgrade an app while retaining data without having the
|
||||
// same signature as the official version. Nor can you post it on
|
||||
// the Play Store, since that application ID is already taken.
|
||||
// Reputable APK hosting websites similarly validate the signature
|
||||
// is consistent with the Play Store and won't allow an APK that
|
||||
// isn't signed the same as the original.
|
||||
//
|
||||
// I wish any and all people using Moonlight as the basis of other
|
||||
// cool projects the best of luck with their efforts. All I ask
|
||||
// is to please change the applicationId before you publish.
|
||||
//
|
||||
// TL;DR: Leave the following line alone!
|
||||
applicationIdSuffix ".unofficial"
|
||||
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt')
|
||||
}
|
||||
|
||||
@@ -304,7 +304,40 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
// If we're using OSC, always set at least gamepad 1.
|
||||
gamepadMask |= 1;
|
||||
}
|
||||
|
||||
|
||||
// Set to the optimal mode for streaming
|
||||
float displayRefreshRate = prepareDisplayForRendering();
|
||||
LimeLog.info("Display refresh rate: "+displayRefreshRate);
|
||||
|
||||
// HACK: Despite many efforts to ensure low latency consistent frame
|
||||
// delivery, the best non-lossy mechanism is to buffer 1 extra frame
|
||||
// in the output pipeline. Android does some buffering on its end
|
||||
// in SurfaceFlinger and it's difficult (impossible?) to inspect
|
||||
// the precise state of the buffer queue to the screen after we
|
||||
// release a frame for rendering.
|
||||
//
|
||||
// Since buffering a frame adds latency and we are primarily a
|
||||
// latency-optimized client, rather than one designed for picture-perfect
|
||||
// accuracy, we will synthetically induce a negative pressure on the display
|
||||
// output pipeline by driving the decoder input pipeline under the speed
|
||||
// that the display can refresh. This ensures a constant negative pressure
|
||||
// to keep latency down but does induce a periodic frame loss. However, this
|
||||
// periodic frame loss is *way* less than what we'd already get in Marshmallow's
|
||||
// display pipeline where frames are dropped outside of our control if they land
|
||||
// on the same V-sync.
|
||||
//
|
||||
// Hopefully, we can get rid of this once someone comes up with a better way
|
||||
// to track the state of the pipeline and time frames.
|
||||
int roundedRefreshRate = Math.round(displayRefreshRate);
|
||||
if (roundedRefreshRate <= 49) {
|
||||
// Let's avoid clearly bogus refresh rates
|
||||
roundedRefreshRate = 60;
|
||||
}
|
||||
if (!prefConfig.disableFrameDrop && prefConfig.fps >= roundedRefreshRate) {
|
||||
prefConfig.fps = roundedRefreshRate - 1;
|
||||
LimeLog.info("Adjusting FPS target for screen to "+prefConfig.fps);
|
||||
}
|
||||
|
||||
StreamConfiguration config = new StreamConfiguration.Builder()
|
||||
.setResolution(prefConfig.width, prefConfig.height)
|
||||
.setRefreshRate(prefConfig.fps)
|
||||
@@ -318,6 +351,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
.setHevcSupported(decoderRenderer.isHevcSupported())
|
||||
.setEnableHdr(willStreamHdr)
|
||||
.setAttachedGamepadMask(gamepadMask)
|
||||
.setClientRefreshRateX100((int)(displayRefreshRate * 100))
|
||||
.setAudioConfiguration(prefConfig.enable51Surround ?
|
||||
MoonBridge.AUDIO_CONFIGURATION_51_SURROUND :
|
||||
MoonBridge.AUDIO_CONFIGURATION_STEREO)
|
||||
@@ -330,9 +364,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||
inputManager.registerInputDeviceListener(controllerHandler, null);
|
||||
|
||||
// Set to the optimal mode for streaming
|
||||
prepareDisplayForRendering();
|
||||
|
||||
// Initialize touch contexts
|
||||
for (int i = 0; i < touchContextMap.length; i++) {
|
||||
touchContextMap[i] = new TouchContext(conn, i,
|
||||
@@ -407,9 +438,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareDisplayForRendering() {
|
||||
private float prepareDisplayForRendering() {
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindow().getAttributes();
|
||||
float displayRefreshRate;
|
||||
|
||||
// On M, we can explicitly set the optimal display mode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
@@ -447,6 +479,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
LimeLog.info("Selected display mode: "+bestMode.getPhysicalWidth()+"x"+
|
||||
bestMode.getPhysicalHeight()+"x"+bestMode.getRefreshRate());
|
||||
windowLayoutParams.preferredDisplayModeId = bestMode.getModeId();
|
||||
displayRefreshRate = bestMode.getRefreshRate();
|
||||
}
|
||||
// On L, we can at least tell the OS that we want 60 Hz
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
@@ -459,6 +492,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
LimeLog.info("Selected refresh rate: "+bestRefreshRate);
|
||||
windowLayoutParams.preferredRefreshRate = bestRefreshRate;
|
||||
displayRefreshRate = bestRefreshRate;
|
||||
}
|
||||
else {
|
||||
// Otherwise, the active display refresh rate is just
|
||||
// whatever is currently in use.
|
||||
displayRefreshRate = display.getRefreshRate();
|
||||
}
|
||||
|
||||
// Apply the display mode change
|
||||
@@ -494,6 +533,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
// Set the surface to scale based on the aspect ratio of the stream
|
||||
streamView.setDesiredAspectRatio((double)prefConfig.width / (double)prefConfig.height);
|
||||
}
|
||||
|
||||
return displayRefreshRate;
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
|
||||
@@ -410,7 +410,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
||||
}
|
||||
|
||||
// Render the last buffer
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && prefs.disableFrameDrop) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// Use a PTS that will cause this frame to never be dropped if frame dropping
|
||||
// is disabled
|
||||
videoDecoder.releaseOutputBuffer(lastIndex, 0);
|
||||
|
||||
@@ -153,27 +153,51 @@ public class MediaCodecHelper {
|
||||
// Qualcomm is currently the only decoders in this group.
|
||||
}
|
||||
|
||||
private static boolean isLowEndSnapdragonRenderer(String glRenderer) {
|
||||
private static String getAdrenoVersionString(String glRenderer) {
|
||||
glRenderer = glRenderer.toLowerCase().trim();
|
||||
|
||||
if (!glRenderer.contains("adreno")) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
Pattern modelNumberPattern = Pattern.compile("(.*)([0-9]{3})(.*)");
|
||||
|
||||
Matcher matcher = modelNumberPattern.matcher(glRenderer);
|
||||
if (!matcher.matches()) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
String modelNumber = matcher.group(2);
|
||||
LimeLog.info("Found Adreno GPU: "+modelNumber);
|
||||
return modelNumber;
|
||||
}
|
||||
|
||||
private static boolean isLowEndSnapdragonRenderer(String glRenderer) {
|
||||
String modelNumber = getAdrenoVersionString(glRenderer);
|
||||
if (modelNumber == null) {
|
||||
// Not an Adreno GPU
|
||||
return false;
|
||||
}
|
||||
|
||||
// The current logic is to identify low-end SoCs based on a zero in the x0x place.
|
||||
return modelNumber.charAt(1) == '0';
|
||||
}
|
||||
|
||||
// This is a workaround for some broken devices that report
|
||||
// only GLES 3.0 even though the GPU is an Adreno 4xx series part.
|
||||
// An example of such a device is the Huawei Honor 5x with the
|
||||
// Snapdragon 616 SoC (Adreno 405).
|
||||
private static boolean isGLES31SnapdragonRenderer(String glRenderer) {
|
||||
String modelNumber = getAdrenoVersionString(glRenderer);
|
||||
if (modelNumber == null) {
|
||||
// Not an Adreno GPU
|
||||
return false;
|
||||
}
|
||||
|
||||
// Snapdragon 4xx and higher support GLES 3.1
|
||||
return modelNumber.charAt(0) >= '4';
|
||||
}
|
||||
|
||||
public static void initialize(Context context, String glRenderer) {
|
||||
if (initialized) {
|
||||
return;
|
||||
@@ -208,9 +232,10 @@ public class MediaCodecHelper {
|
||||
// 3xx - bad
|
||||
// 4xx - good
|
||||
//
|
||||
// Unfortunately, it's not that easy to get that information here, so I'll use an
|
||||
// approximation by checking the GLES level (<= 3.0 is bad).
|
||||
if (configInfo.reqGlEsVersion > 0x30000) {
|
||||
// The "good" GPUs support GLES 3.1, but we can't just check that directly
|
||||
// (see comment on isGLES31SnapdragonRenderer).
|
||||
//
|
||||
if (isGLES31SnapdragonRenderer(glRenderer)) {
|
||||
// We prefer reference frame invalidation support (which is only doable on AVC on
|
||||
// older Qualcomm chips) vs. enabling HEVC by default. The user can override using the settings
|
||||
// to force HEVC on. If HDR or mobile data will be used, we'll override this and use
|
||||
|
||||
+1
-1
Submodule moonlight-common updated: 52e09a1e69...8a89f2ff82
Reference in New Issue
Block a user