diff --git a/app/src/main/java/app/gamenative/display/GameNativeDrm.kt b/app/src/main/java/app/gamenative/display/GameNativeDrm.kt index 4356c5f4de..cdffd9b24d 100644 --- a/app/src/main/java/app/gamenative/display/GameNativeDrm.kt +++ b/app/src/main/java/app/gamenative/display/GameNativeDrm.kt @@ -41,6 +41,10 @@ object GameNativeDrm { @JvmStatic external fun nativeStop() + /** The scan-out pool layout the running session chose, "bgra" or "rgba"; valid after [nativeStart]. */ + @JvmStatic + external fun nativeScanoutLayout(): String + /** * Adopt a new display window for a RUNNING session without ending it: rebuild the publish * layer from [surface] and re-present the retained last frame, so a display power cycle keeps diff --git a/app/src/main/java/app/gamenative/display/GamescopePayload.kt b/app/src/main/java/app/gamenative/display/GamescopePayload.kt index 2633ed403d..dbf2d49281 100644 --- a/app/src/main/java/app/gamenative/display/GamescopePayload.kt +++ b/app/src/main/java/app/gamenative/display/GamescopePayload.kt @@ -11,7 +11,7 @@ import java.io.File /** Versioned gamescope payload (gamescope, XWayland, scaling clients), fetched on the first gamescope launch. */ object GamescopePayload { - const val VERSION = "20261029.1" + const val VERSION = "20261029.3" const val ARCHIVE = "gamescope-gamenative-$VERSION.tzst" private const val STAMP = ".payload.version" diff --git a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt index 93f9519cd1..13dff9d07f 100644 --- a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt +++ b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt @@ -2069,6 +2069,9 @@ fun XServerScreen( } SessionDisplay.GAMESCOPE -> { (xServerViewInstance as XServerView).isGamescopeMode = true + xServerViewInstance.setScanoutLayoutOverride( + EnvVars(container.envVars).get("GNDRM_SCANOUT_LAYOUT"), + ) xServerToUse.setInputEventSink(GamescopeInputSink()) // Ahead of nativeStart, which fixes the emulated mode's rate from this // view's surface callback, so the panel's real rate must be set first. diff --git a/app/src/main/java/com/winlator/widget/XServerView.java b/app/src/main/java/com/winlator/widget/XServerView.java index ab8d4f7526..be74e0498a 100644 --- a/app/src/main/java/com/winlator/widget/XServerView.java +++ b/app/src/main/java/com/winlator/widget/XServerView.java @@ -2,6 +2,8 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.system.ErrnoException; +import android.system.Os; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup; @@ -20,6 +22,7 @@ import app.gamenative.PluviaApp; import app.gamenative.display.GameNativeDrm; +import timber.log.Timber; @SuppressLint("ViewConstructor") public class XServerView extends SurfaceView implements SurfaceHolder.Callback, XServerRendererView { @@ -57,6 +60,12 @@ public boolean isGamescopeMode() { return gamescopeMode; } + private String scanoutLayoutOverride; + + public void setScanoutLayoutOverride(String scanoutLayoutOverride) { + this.scanoutLayoutOverride = scanoutLayoutOverride; + } + public XServerRenderer getRenderer() { return renderer; } @@ -80,6 +89,14 @@ public void surfaceCreated(@NonNull SurfaceHolder holder) { // when none is running. int rc = GameNativeDrm.nativeRetargetSurface(holder.getSurface(), defaultSize[0], defaultSize[1]); if (rc == GameNativeDrm.E_NO_SESSION) { + try { + if (scanoutLayoutOverride != null && !scanoutLayoutOverride.isEmpty()) + Os.setenv("GNDRM_SCANOUT_LAYOUT", scanoutLayoutOverride, true); + else + Os.unsetenv("GNDRM_SCANOUT_LAYOUT"); + } catch (ErrnoException e) { + Timber.w(e, "Could not set GNDRM_SCANOUT_LAYOUT"); + } GameNativeDrm.nativeStart("gndrm", holder.getSurface(), defaultSize[0], defaultSize[1]); } return; diff --git a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java index f0c4601bd1..293e25cac7 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java @@ -20,6 +20,7 @@ import com.winlator.PrefManager; import app.gamenative.PluviaApp; +import app.gamenative.display.GameNativeDrm; import app.gamenative.display.GamescopeSettings; import app.gamenative.utils.LsfgQuickMenuHelper; import app.gamenative.utils.LsfgVkManager; @@ -526,6 +527,8 @@ private void applyGamescopeEnv(Context context, EnvVars envVars, File rootDir) { FileUtils.chmod(xdgRunDir, 0700); envVars.put("XDG_RUNTIME_DIR", xdgRunDir.getPath()); envVars.put("GAMENATIVE_DRM_SOCKET", "gndrm"); + if (!envVars.has("GNDRM_SCANOUT_LAYOUT")) + envVars.put("GNDRM_SCANOUT_LAYOUT", scanoutLayout(context)); envVars.put("XKB_CONFIG_ROOT", gsDir + "/share/xkeyboard-config-2"); envVars.put("GAMESCOPE_PNP_IDS_PATH", gsDir + "/share/hwdata/pnp.ids"); @@ -573,6 +576,14 @@ private void applyGamescopeEnv(Context context, EnvVars envVars, File rootDir) { + new File(gsDir, "bin/Xwayland").exists() + " xdg=" + xdgRunDir.getPath()); } + private static String scanoutLayout(Context context) { + try { + return GameNativeDrm.nativeScanoutLayout(); + } catch (LinkageError e) { + return "bgra"; + } + } + /** Mirrors XServerScreen.resolveGamescopeMode; a session override (setGamescopeModeOverride) wins to force X11 for the open-container session (the setup/pre-install session has no separate arm and follows the game arm). */ private boolean isGamescopeMode() { if (gamescopeModeOverride != null) return gamescopeModeOverride; diff --git a/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so b/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so index 7b46df8445..79f6cd490e 100755 Binary files a/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so and b/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so differ