2
0
Milan Jurkulak 3 сар өмнө
parent
commit
0fb61842f5

+ 3 - 0
compositor/compositor.gradle.kts

@@ -118,6 +118,9 @@ kotlin {
                 linkerOpts(systemLibDirs)
                 linkerOpts(shimDir.get().asFile.resolve("libmjcshim.a").absolutePath)
                 linkerOpts(wlrLibs)
+                // the shim queries GL_RENDERER via EGL to decide hardware vs software GL for the
+                // shell (SKIKO_RENDER_API), so link the EGL + GLES2 dispatchers explicitly.
+                linkerOpts("-lEGL", "-lGLESv2")
             }
         }
     }

+ 46 - 0
compositor/native/shim.c

@@ -28,6 +28,10 @@
 #include <wlr/backend/session.h>
 #include <wlr/render/allocator.h>
 #include <wlr/render/wlr_renderer.h>
+#include <wlr/render/gles2.h>
+#include <wlr/render/egl.h>
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
 #include <wlr/types/wlr_compositor.h>
 #include <wlr/types/wlr_subcompositor.h>
 #include <wlr/types/wlr_cursor.h>
@@ -1239,6 +1243,38 @@ static int handle_sigchld(int signal_number, void *data) {
     return 0;
 }
 
+/* True when the GLES2 renderer ended up on software rendering (llvmpipe/swrast) — i.e. there is
+ * no usable hardware GL. In that case the Compose shell (Skiko) cannot create an OpenGL/GLX
+ * context on the (also software) XWayland and must use its CPU raster backend, so the compositor
+ * exports SKIKO_RENDER_API=SOFTWARE for the shell. On a real GPU it returns false and the shell
+ * uses hardware GL. Queries GL_RENDERER via the renderer's own EGL context (surfaceless). */
+static bool mjc_renderer_is_software(struct wlr_renderer *renderer) {
+    if (!wlr_renderer_is_gles2(renderer)) {
+        return false;
+    }
+    struct wlr_egl *egl = wlr_gles2_renderer_get_egl(renderer);
+    if (egl == NULL) {
+        return false;
+    }
+    EGLDisplay dpy = wlr_egl_get_display(egl);
+    EGLContext ctx = wlr_egl_get_context(egl);
+    if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
+        return false;
+    }
+    if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
+        return false;
+    }
+    const char *gl_renderer = (const char *) glGetString(GL_RENDERER);
+    bool software = gl_renderer != NULL && (
+        strstr(gl_renderer, "llvmpipe") != NULL ||
+        strstr(gl_renderer, "softpipe") != NULL ||
+        strstr(gl_renderer, "swrast") != NULL ||
+        strstr(gl_renderer, "SWR") != NULL ||
+        strstr(gl_renderer, "Software") != NULL);
+    eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    return software;
+}
+
 /* ------------------------------------------------------------------ */
 /* public API                                                          */
 /* ------------------------------------------------------------------ */
@@ -1369,6 +1405,16 @@ bool mjc_start(mjc_server *server, const mjc_callbacks *callbacks, void *userdat
     if (server->xwayland != NULL) {
         setenv("DISPLAY", server->xwayland->display_name, true);
     }
+    /* GPU vs software decision for the Compose shell (Skiko), exported into its environment
+     * before it is spawned. Software GL (VM / no GPU) -> Skiko CPU raster (else it crashes with
+     * "Cannot create Linux GL context"); real GPU -> leave unset so Skiko uses hardware GL. */
+    if (mjc_renderer_is_software(server->renderer)) {
+        setenv("SKIKO_RENDER_API", "SOFTWARE", true);
+        fprintf(stderr, "mjdevc: software GL renderer -> SKIKO_RENDER_API=SOFTWARE for the shell\n");
+    } else {
+        unsetenv("SKIKO_RENDER_API");
+        fprintf(stderr, "mjdevc: hardware GL renderer -> shell uses Skiko OpenGL\n");
+    }
 
     if (server->cbs.ready != NULL) {
         server->cbs.ready(server->ud);

+ 3 - 6
session/mjdev-session

@@ -13,12 +13,9 @@ export _JAVA_AWT_WM_NONREPARENTING=1
 # rendering detected, please use WLR_RENDERER_ALLOW_SOFTWARE") and the compositor
 # exits immediately -> black screen + tty1 autologin crash-loop.
 export WLR_RENDERER_ALLOW_SOFTWARE=1
-# the Compose shell renders via Skiko. On a software/llvmpipe stack (VM, or a box with
-# no GPU) the compositor's XWayland has no glamor, so Skiko cannot create an OpenGL/GLX
-# context -> "org.jetbrains.skiko.RenderException: Cannot create Linux GL context" and the
-# shell crash-loops. Skiko's CPU raster backend needs no GL context and works everywhere.
-# (On real GPUs this is the safe-but-slower path; revisit once GPU detection is added.)
-export SKIKO_RENDER_API=SOFTWARE
+# NOTE: SKIKO_RENDER_API is intentionally NOT set here. The compositor (mjdevc) detects at runtime
+# whether it got a hardware or software GL renderer and exports SKIKO_RENDER_API=SOFTWARE for the
+# shell only when GL is software (VM / no GPU) — so real GPUs use hardware GL automatically.
 
 # desktop shell binary - deb/appimage install location, gradle dev fallback
 SHELL_CMD="/opt/mjdev-desktop/bin/mjdev-desktop"