Ver código fonte

kmsdrm: Instead of demanding ARGB8888, try to find a supported surface format.

Fixes #16136.
Ryan C. Gordon 1 semana atrás
pai
commit
68655e9772
1 arquivos alterados com 96 adições e 50 exclusões
  1. 96 50
      src/video/kmsdrm/SDL_kmsdrmvideo.c

+ 96 - 50
src/video/kmsdrm/SDL_kmsdrmvideo.c

@@ -1768,78 +1768,124 @@ static void KMSDRM_DirtySurfaces(SDL_Window *window)
    that we create here. */
    that we create here. */
 bool KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window)
 bool KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window)
 {
 {
+    static const struct { uint32_t fmt; const char *name; int r; int g; int b; int a; } gbm_formats[] = {
+        // !!! FIXME: I have no idea if this is a good preferred order for this list.
+        #define FMT(name, r, g, b, a) { GBM_FORMAT_##name, #name, r, g, b, a }
+        FMT(ARGB8888, 8, 8, 8, 8),
+        FMT(ABGR8888, 8, 8, 8, 8),
+        FMT(BGRA8888, 8, 8, 8, 8),
+        FMT(RGBA8888, 8, 8, 8, 8),
+        FMT(BGRX8888, 8, 8, 8, 0),
+        FMT(RGBX8888, 8, 8, 8, 0),
+        FMT(XRGB8888, 8, 8, 8, 0),
+        FMT(XBGR8888, 8, 8, 8, 0),
+        FMT(RGBA1010102, 10, 10, 10, 2),
+        FMT(BGRA1010102, 10, 10, 10, 2),
+        FMT(ARGB2101010, 10, 10, 10, 2),
+        FMT(ABGR2101010, 10, 10, 10, 2),
+        FMT(XRGB2101010, 10, 10, 10, 0),
+        FMT(XBGR2101010, 10, 10, 10, 0),
+        FMT(RGBX1010102, 10, 10, 10, 0),
+        FMT(BGRX1010102, 10, 10, 10, 0),
+        FMT(ARGB1555, 5, 5, 5, 1),
+        FMT(ABGR1555, 5, 5, 5, 1),
+        FMT(RGBA5551, 5, 5, 5, 1),
+        FMT(BGRA5551, 5, 5, 5, 1),
+        FMT(XRGB1555, 5, 5, 5, 0),
+        FMT(XBGR1555, 5, 5, 5, 0),
+        FMT(RGBX5551, 5, 5, 5, 0),
+        FMT(BGRX5551, 5, 5, 5, 0),
+        FMT(RGB565, 5, 6, 5, 0),
+        FMT(BGR565, 5, 6, 5, 0)
+        #undef FMT
+    };
+
     SDL_VideoData *viddata = _this->internal;
     SDL_VideoData *viddata = _this->internal;
     SDL_WindowData *windata = window->internal;
     SDL_WindowData *windata = window->internal;
     SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
     SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
     SDL_DisplayData *dispdata = display->internal;
     SDL_DisplayData *dispdata = display->internal;
-
-    uint32_t surface_fmt = GBM_FORMAT_ARGB8888;
-    uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
-
     EGLContext egl_context;
     EGLContext egl_context;
-
-    bool result = true;
+    bool result = false;
 
 
     // If the current window already has surfaces, destroy them before creating other.
     // If the current window already has surfaces, destroy them before creating other.
     if (windata->gs) {
     if (windata->gs) {
         KMSDRM_DestroySurfaces(_this, window);
         KMSDRM_DestroySurfaces(_this, window);
     }
     }
 
 
-    if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev,
-                                               surface_fmt, surface_flags)) {
-        SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO,
-                    "GBM surface format not supported. Trying anyway.");
-    }
+    bool tried_setting_format = false;
+    const uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+    for (int i = 0; i < SDL_arraysize(gbm_formats); i++) {
+        const uint32_t surface_fmt = gbm_formats[i].fmt;
+
+        SDL_Log("KMSDRM: Trying format GBM_FORMAT_%s", gbm_formats[i].name);
 
 
-    /* The KMSDRM backend doesn't always set the mode the higher-level code in
-       SDL_video.c expects. Hulk-smash the display's current_mode to keep the
-       mode that's set in sync with what SDL_video.c thinks is set
+        if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) {
+            SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "KMSDRM: GBM_FORMAT_%s is not supported.", gbm_formats[i].name);
+            continue;  // try the next one.
+        }
 
 
-       FIXME: How do we do that now? Can we get a better idea at the higher level?
-     */
-    KMSDRM_GetModeToSet(window, &dispdata->mode);
+        tried_setting_format = true;
 
 
-    windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
-                                            dispdata->mode.hdisplay, dispdata->mode.vdisplay,
-                                            surface_fmt, surface_flags);
-    if (!windata->gs && errno == ENOSYS) {
-        // Try again without the scanout flags, needed on NVIDIA drivers
-        windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
-                                                dispdata->mode.hdisplay, dispdata->mode.vdisplay,
-                                                surface_fmt, 0);
-    }
-    if (!windata->gs) {
-        return SDL_SetError("Could not create GBM surface: %s", strerror(errno));
-    }
+        /* The KMSDRM backend doesn't always set the mode the higher-level code in
+           SDL_video.c expects. Hulk-smash the display's current_mode to keep the
+           mode that's set in sync with what SDL_video.c thinks is set
 
 
-    /* We can't get the EGL context yet because SDL_CreateRenderer has not been called,
-       but we need an EGL surface NOW, or GL won't be able to render into any surface
-       and we won't see the first frame. */
-    SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
-    windata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)windata->gs);
+           FIXME: How do we do that now? Can we get a better idea at the higher level?
+         */
+        KMSDRM_GetModeToSet(window, &dispdata->mode);
 
 
-    if (windata->egl_surface == EGL_NO_SURFACE) {
-        result = SDL_SetError("Could not create EGL window surface");
-        goto cleanup;
-    }
+        windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, dispdata->mode.hdisplay, dispdata->mode.vdisplay, surface_fmt, surface_flags);
+        if (!windata->gs && errno == ENOSYS) {
+            // Try again without the scanout flags, needed on NVIDIA drivers
+            windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, dispdata->mode.hdisplay, dispdata->mode.vdisplay, surface_fmt, 0);
+        }
+        if (!windata->gs) {
+            SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "KMSDRM: gbm_surface_create(GBM_FORMAT_%s) failed.", gbm_formats[i].name);
+            SDL_SetError("Could not create %s GBM surface: %s", gbm_formats[i].name, strerror(errno));  // set error in case this was the last supposedly-supported format.
+            continue;   // try the next one.
+        }
 
 
-    /* Current context passing to EGL is now done here. If something fails,
-       go back to delayed SDL_EGL_MakeCurrent() call in SwapWindow. */
-    egl_context = (EGLContext)SDL_GL_GetCurrentContext();
-    result = SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
+        /* We can't get the EGL context yet because SDL_CreateRenderer has not been called,
+           but we need an EGL surface NOW, or GL won't be able to render into any surface
+           and we won't see the first frame. */
+        SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
+        windata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)windata->gs);
+        if (windata->egl_surface == EGL_NO_SURFACE) {
+            SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "KMSDRM: SDL_EGL_CreateSurface(GBM_FORMAT_%s) failed: %s", gbm_formats[i].name, SDL_GetError());
+            KMSDRM_gbm_surface_destroy(windata->gs);
+            windata->gs = NULL;
+            continue;  // try the next one.
+        }
 
 
-    SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED,
-                        dispdata->mode.hdisplay, dispdata->mode.vdisplay);
+        /* Current context passing to EGL is now done here. If something fails,
+           go back to delayed SDL_EGL_MakeCurrent() call in SwapWindow. */
+        egl_context = (EGLContext)SDL_GL_GetCurrentContext();
+        result = SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
+        if (!result) {
+            SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "KMSDRM: SDL_EGL_MakeCurrent with GBM_FORMAT_%s failed: %s", gbm_formats[i].name, SDL_GetError());
+            continue;
+        }
 
 
-    windata->egl_surface_dirty = false;
+        _this->gl_config.red_size = gbm_formats[i].r;
+        _this->gl_config.green_size = gbm_formats[i].g;
+        _this->gl_config.blue_size = gbm_formats[i].b;
+        _this->gl_config.alpha_size = gbm_formats[i].a;
 
 
-cleanup:
+        windata->egl_surface_dirty = false;
+
+        result = true;
+
+        SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, dispdata->mode.hdisplay, dispdata->mode.vdisplay);
+
+        break;
+    }
+
+    SDL_assert(result || (windata->gs == NULL));
 
 
     if (!result) {
     if (!result) {
-        // Error (complete) cleanup.
-        if (windata->gs) {
-            KMSDRM_gbm_surface_destroy(windata->gs);
-            windata->gs = NULL;
+        SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "KMSDRM: Failed to create surfaces in _any_ format!");
+        if (!tried_setting_format) {   // make sure there's an error string set.
+            SDL_SetError("Could not find any supported GBM surface format.");
         }
         }
     }
     }