Edit

IABSD.fr/xenocara/lib/mesa/src/loader/loader_dri_helper.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/loader/loader_dri_helper.c
  • /*
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that copyright
     * notice and this permission notice appear in supporting documentation, and
     * that the name of the copyright holders not be used in advertising or
     * publicity pertaining to distribution of the software without specific,
     * written prior permission.  The copyright holders make no representations
     * about the suitability of this software for any purpose.  It is provided "as
     * is" without express or implied warranty.
     *
     * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     * OF THIS SOFTWARE.
     */
    
    #include <errno.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    #include <GL/gl.h> /* mesa_interface needs GL types */
    #include "mesa_interface.h"
    
    #include "drm-uapi/drm_fourcc.h"
    #include "loader_dri_helper.h"
    #include "util/driconf.h"
    
    
    /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
     * the createImageFromDmaBufs call takes DRM_FORMAT codes. To avoid
     * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
     * translate to DRM_FORMAT codes in the call to createImageFromDmaBufs
     */
    int
    loader_fourcc_to_image_format(int fourcc)
    {
       /* Convert from DRM_FORMAT to __DRI_IMAGE_FORMAT (sigh) */
       switch (fourcc) {
       case __DRI_IMAGE_FOURCC_SARGB8888: return __DRI_IMAGE_FORMAT_SARGB8;
       case __DRI_IMAGE_FOURCC_SABGR8888: return __DRI_IMAGE_FORMAT_SABGR8;
       case __DRI_IMAGE_FOURCC_SXRGB8888: return __DRI_IMAGE_FORMAT_SXRGB8;
       case DRM_FORMAT_RGB565: return __DRI_IMAGE_FORMAT_RGB565;
       case DRM_FORMAT_ARGB1555: return __DRI_IMAGE_FORMAT_ARGB1555;
       case DRM_FORMAT_XRGB8888: return __DRI_IMAGE_FORMAT_XRGB8888;
       case DRM_FORMAT_ARGB8888: return __DRI_IMAGE_FORMAT_ARGB8888;
       case DRM_FORMAT_ABGR8888: return __DRI_IMAGE_FORMAT_ABGR8888;
       case DRM_FORMAT_XBGR8888: return __DRI_IMAGE_FORMAT_XBGR8888;
       case DRM_FORMAT_XRGB2101010: return __DRI_IMAGE_FORMAT_XRGB2101010;
       case DRM_FORMAT_ARGB2101010: return __DRI_IMAGE_FORMAT_ARGB2101010;
       case DRM_FORMAT_XBGR2101010: return __DRI_IMAGE_FORMAT_XBGR2101010;
       case DRM_FORMAT_ABGR2101010: return __DRI_IMAGE_FORMAT_ABGR2101010;
       case DRM_FORMAT_ABGR16161616: return __DRI_IMAGE_FORMAT_ABGR16161616;
       case DRM_FORMAT_XBGR16161616: return __DRI_IMAGE_FORMAT_XBGR16161616;
       case DRM_FORMAT_XBGR16161616F: return __DRI_IMAGE_FORMAT_XBGR16161616F;
       case DRM_FORMAT_ABGR16161616F: return __DRI_IMAGE_FORMAT_ABGR16161616F;
       }
       return 0;
    }
    
    int
    loader_image_format_to_fourcc(int format)
    {
       /* Convert from __DRI_IMAGE_FORMAT to DRM_FORMAT (sigh) */
       switch (format) {
       case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
       case __DRI_IMAGE_FORMAT_SABGR8: return __DRI_IMAGE_FOURCC_SABGR8888;
       case __DRI_IMAGE_FORMAT_SXRGB8: return __DRI_IMAGE_FOURCC_SXRGB8888;
       case __DRI_IMAGE_FORMAT_RGB565: return DRM_FORMAT_RGB565;
       case __DRI_IMAGE_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
       case __DRI_IMAGE_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
       case __DRI_IMAGE_FORMAT_ABGR8888: return DRM_FORMAT_ABGR8888;
       case __DRI_IMAGE_FORMAT_XBGR8888: return DRM_FORMAT_XBGR8888;
       case __DRI_IMAGE_FORMAT_XRGB2101010: return DRM_FORMAT_XRGB2101010;
       case __DRI_IMAGE_FORMAT_ARGB2101010: return DRM_FORMAT_ARGB2101010;
       case __DRI_IMAGE_FORMAT_XBGR2101010: return DRM_FORMAT_XBGR2101010;
       case __DRI_IMAGE_FORMAT_ABGR2101010: return DRM_FORMAT_ABGR2101010;
       case __DRI_IMAGE_FORMAT_ABGR16161616: return DRM_FORMAT_ABGR16161616;
       case __DRI_IMAGE_FORMAT_XBGR16161616: return DRM_FORMAT_XBGR16161616;
       case __DRI_IMAGE_FORMAT_XBGR16161616F: return DRM_FORMAT_XBGR16161616F;
       case __DRI_IMAGE_FORMAT_ABGR16161616F: return DRM_FORMAT_ABGR16161616F;
       case __DRI_IMAGE_FORMAT_ARGB1555: return DRM_FORMAT_ARGB1555;
       }
       return 0;
    }
    
    #ifdef HAVE_X11_PLATFORM
    void
    loader_init_screen_resources(struct loader_screen_resources *res,
                                 xcb_connection_t *conn,
                                 xcb_screen_t *screen)
    {
       res->conn = conn;
       res->screen = screen;
       res->crtcs = NULL;
    
       mtx_init(&res->mtx, mtx_plain);
    }
    
    void
    loader_destroy_screen_resources(struct loader_screen_resources *res)
    {
       mtx_destroy(&res->mtx);
    }
    
    static unsigned
    gcd_u32(unsigned a, unsigned b)
    {
       assert(a > 0 || b > 0);
    
       while (b != 0) {
          unsigned remainder = a % b;
          a = b;
          b = remainder;
       }
    
       return a;
    }
    
    static void
    calculate_refresh_rate(const xcb_randr_mode_info_t *mode,
                           unsigned *numerator, unsigned *denominator)
    {
       unsigned vtotal = mode->vtotal;
    
       /* Double-scan doubles the number of lines */
       if (mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN)
          vtotal *= 2;
    
       /* Interlace splits the frame into two fields; typically the monitor
        * reports field rate.
        */
       if (mode->mode_flags & XCB_RANDR_MODE_FLAG_INTERLACE)
          vtotal /= 2;
    
       uint32_t dots = mode->htotal * vtotal;
    
       if (dots == 0) {
          *numerator = 0;
          *denominator = 1;
       } else {
          uint32_t gcd = gcd_u32(mode->dot_clock, dots);
    
          *numerator = mode->dot_clock / gcd;
          *denominator = dots / gcd;
       }
    }
    
    bool
    loader_update_screen_resources(struct loader_screen_resources *res)
    {
       xcb_randr_get_crtc_info_cookie_t *crtc_cookies;
    
       /* If we have cached screen resources information, check each CRTC to
        * see if it's up to date.  Ideally, we'd watch PresentConfigureNotify
        * events on the root window to see if something changed, but those only
        * fire if the geometry changes.  It misses CRTC changes which only
        * alter the refresh rate.  We also can't watch RandR events internally
        * because they aren't XGE events.  So, we just check every CRTC for now.
        */
       bool config_unchanged = res->crtcs != NULL;
    
       crtc_cookies = malloc(res->num_crtcs * sizeof(*crtc_cookies));
    
       for (unsigned c = 0; c < res->num_crtcs; c++) {
          crtc_cookies[c] =
             xcb_randr_get_crtc_info_unchecked(res->conn, res->crtcs[c].id,
                                               res->config_timestamp);
       }
    
       for (unsigned c = 0; c < res->num_crtcs; c++) {
          xcb_randr_get_crtc_info_reply_t *reply =
             xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL);
    
          /* Although randrproto 1.4.0 says that RRGetCrtcInfo is supposed to
           * return InvalidConfigTime if config_timestamp is out of date, the
           * implementation in xserver as of 21.x doesn't actually do so.  To
           * detect changes in refresh rate, we check the returned timestamp
           * on each tracked CRTC.
           */
          if (!reply ||
              reply->status == XCB_RANDR_SET_CONFIG_INVALID_CONFIG_TIME ||
              reply->timestamp != res->crtcs[c].timestamp) {
             config_unchanged = false;
             /* continue to consume all replies */
          }
    
          free(reply);
       }
    
       free(crtc_cookies);
    
       if (config_unchanged)
          return false;
    
       /* Do RRGetScreenResourcesCurrent to query the list of CRTCs and modes,
        * then RRGetCrtcInfo on each CRTC to determine what mode each uses, and
        * use the mode to calculate the refresh rate.
        */
       mtx_lock(&res->mtx);
    
       xcb_randr_get_screen_resources_current_cookie_t cookie =
          xcb_randr_get_screen_resources_current_unchecked(res->conn,
                                                           res->screen->root);
       xcb_randr_get_screen_resources_current_reply_t *reply =
          xcb_randr_get_screen_resources_current_reply(res->conn, cookie, NULL);
    
       xcb_randr_crtc_t *new_crtcs =
          xcb_randr_get_screen_resources_current_crtcs(reply);
    
       xcb_randr_mode_info_t *new_modes =
          xcb_randr_get_screen_resources_current_modes(reply);
    
       res->config_timestamp = reply->config_timestamp;
    
       free(res->crtcs);
       res->crtcs = calloc(reply->num_crtcs, sizeof(*res->crtcs));
    
       crtc_cookies = malloc(reply->num_crtcs * sizeof(*crtc_cookies));
    
       for (unsigned c = 0; c < reply->num_crtcs; c++) {
          crtc_cookies[c] =
             xcb_randr_get_crtc_info_unchecked(res->conn, new_crtcs[c],
                                               res->config_timestamp);
       }
    
       unsigned i = 0;
       for (unsigned c = 0; c < reply->num_crtcs; c++) {
          xcb_randr_get_crtc_info_reply_t *crtc_info =
             xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL);
    
          if (!crtc_info || crtc_info->mode == XCB_NONE)
             continue;
    
          res->crtcs[i].id = new_crtcs[c];
          res->crtcs[i].timestamp = crtc_info->timestamp;
          res->crtcs[i].x = crtc_info->x;
          res->crtcs[i].y = crtc_info->y;
          res->crtcs[i].width = crtc_info->width;
          res->crtcs[i].height = crtc_info->height;
    
          for (int m = 0; m < reply->num_modes; m++) {
             if (new_modes[m].id == crtc_info->mode) {
                calculate_refresh_rate(&new_modes[m],
                                       &res->crtcs[i].refresh_numerator,
                                       &res->crtcs[i].refresh_denominator);
                break;
             }
          }
    
          i++;
          free(crtc_info);
       }
    
       res->num_crtcs = i;
    
       free(crtc_cookies);
       free(reply);
    
       mtx_unlock(&res->mtx);
       return true;
    }
    #endif