"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/egl/drivers/dri2/platform_device.c" (16 Sep 2020, 11076 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "platform_device.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    1 /*
    2  * Mesa 3-D graphics library
    3  *
    4  * Copyright 2018 Collabora
    5  *
    6  * Based on platform_surfaceless, which has:
    7  *
    8  * Copyright (c) 2014 The Chromium OS Authors.
    9  * Copyright © 2011 Intel Corporation
   10  *
   11  * Permission is hereby granted, free of charge, to any person obtaining a
   12  * copy of this software and associated documentation files (the "Software"),
   13  * to deal in the Software without restriction, including without limitation
   14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   15  * and/or sell copies of the Software, and to permit persons to whom the
   16  * Software is furnished to do so, subject to the following conditions:
   17  *
   18  * The above copyright notice and this permission notice shall be included
   19  * in all copies or substantial portions of the Software.
   20  *
   21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   27  * DEALINGS IN THE SOFTWARE.
   28  */
   29 #ifdef HAVE_LIBDRM
   30 #include <xf86drm.h>
   31 #endif
   32 
   33 #include <stdlib.h>
   34 #include <stdio.h>
   35 #include <string.h>
   36 #include <dlfcn.h>
   37 #include <sys/types.h>
   38 #include <sys/stat.h>
   39 #include <fcntl.h>
   40 #include <unistd.h>
   41 
   42 #include "egl_dri2.h"
   43 #include "egl_dri2_fallbacks.h"
   44 #include "loader.h"
   45 
   46 static __DRIimage*
   47 device_alloc_image(struct dri2_egl_display *dri2_dpy,
   48                    struct dri2_egl_surface *dri2_surf)
   49 {
   50    return dri2_dpy->image->createImage(
   51             dri2_dpy->dri_screen,
   52             dri2_surf->base.Width,
   53             dri2_surf->base.Height,
   54             dri2_surf->visual,
   55             0,
   56             NULL);
   57 }
   58 
   59 static void
   60 device_free_images(struct dri2_egl_surface *dri2_surf)
   61 {
   62    struct dri2_egl_display *dri2_dpy =
   63       dri2_egl_display(dri2_surf->base.Resource.Display);
   64 
   65    if (dri2_surf->front) {
   66       dri2_dpy->image->destroyImage(dri2_surf->front);
   67       dri2_surf->front = NULL;
   68    }
   69 
   70    free(dri2_surf->swrast_device_buffer);
   71    dri2_surf->swrast_device_buffer = NULL;
   72 }
   73 
   74 static int
   75 device_image_get_buffers(__DRIdrawable *driDrawable,
   76                          unsigned int format,
   77                          uint32_t *stamp,
   78                          void *loaderPrivate,
   79                          uint32_t buffer_mask,
   80                          struct __DRIimageList *buffers)
   81 {
   82    struct dri2_egl_surface *dri2_surf = loaderPrivate;
   83    struct dri2_egl_display *dri2_dpy =
   84       dri2_egl_display(dri2_surf->base.Resource.Display);
   85 
   86    buffers->image_mask = 0;
   87    buffers->front = NULL;
   88    buffers->back = NULL;
   89 
   90    /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
   91     * the spec states that they have a back buffer but no front buffer, in
   92     * contrast to pixmaps, which have a front buffer but no back buffer.
   93     *
   94     * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
   95     * from the spec, following the precedent of Mesa's EGL X11 platform. The
   96     * X11 platform correctly assigns pbuffers to single-buffered configs, but
   97     * assigns the pbuffer a front buffer instead of a back buffer.
   98     *
   99     * Pbuffers in the X11 platform mostly work today, so let's just copy its
  100     * behavior instead of trying to fix (and hence potentially breaking) the
  101     * world.
  102     */
  103 
  104    if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
  105 
  106       if (!dri2_surf->front)
  107          dri2_surf->front =
  108             device_alloc_image(dri2_dpy, dri2_surf);
  109 
  110       buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
  111       buffers->front = dri2_surf->front;
  112    }
  113 
  114    return 1;
  115 }
  116 
  117 static _EGLSurface *
  118 dri2_device_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
  119                            _EGLConfig *conf, const EGLint *attrib_list)
  120 {
  121    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  122    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
  123    struct dri2_egl_surface *dri2_surf;
  124    const __DRIconfig *config;
  125 
  126    /* Make sure to calloc so all pointers
  127     * are originally NULL.
  128     */
  129    dri2_surf = calloc(1, sizeof *dri2_surf);
  130 
  131    if (!dri2_surf) {
  132       _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
  133       return NULL;
  134    }
  135 
  136    if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
  137                           false, NULL))
  138       goto cleanup_surface;
  139 
  140    config = dri2_get_dri_config(dri2_conf, type,
  141                                 dri2_surf->base.GLColorspace);
  142 
  143    if (!config) {
  144       _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
  145       goto cleanup_surface;
  146    }
  147 
  148    dri2_surf->visual = dri2_image_format_for_pbuffer_config(dri2_dpy, config);
  149    if (dri2_surf->visual == __DRI_IMAGE_FORMAT_NONE)
  150       goto cleanup_surface;
  151 
  152    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
  153       goto cleanup_surface;
  154 
  155    return &dri2_surf->base;
  156 
  157    cleanup_surface:
  158       free(dri2_surf);
  159       return NULL;
  160 }
  161 
  162 static EGLBoolean
  163 device_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
  164 {
  165    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  166    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
  167 
  168    device_free_images(dri2_surf);
  169 
  170    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
  171 
  172    dri2_fini_surface(surf);
  173    free(dri2_surf);
  174    return EGL_TRUE;
  175 }
  176 
  177 static _EGLSurface *
  178 dri2_device_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
  179                                    _EGLConfig *conf, const EGLint *attrib_list)
  180 {
  181    return dri2_device_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
  182                                      attrib_list);
  183 }
  184 
  185 static const struct dri2_egl_display_vtbl dri2_device_display_vtbl = {
  186    .create_pixmap_surface = dri2_fallback_create_pixmap_surface,
  187    .create_pbuffer_surface = dri2_device_create_pbuffer_surface,
  188    .destroy_surface = device_destroy_surface,
  189    .create_image = dri2_create_image_khr,
  190    .swap_buffers_region = dri2_fallback_swap_buffers_region,
  191    .post_sub_buffer = dri2_fallback_post_sub_buffer,
  192    .copy_buffers = dri2_fallback_copy_buffers,
  193    .query_buffer_age = dri2_fallback_query_buffer_age,
  194    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
  195    .get_sync_values = dri2_fallback_get_sync_values,
  196    .get_dri_drawable = dri2_surface_get_dri_drawable,
  197 };
  198 
  199 static void
  200 device_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
  201 {
  202 }
  203 
  204 static const __DRIimageLoaderExtension image_loader_extension = {
  205    .base             = { __DRI_IMAGE_LOADER, 1 },
  206    .getBuffers       = device_image_get_buffers,
  207    .flushFrontBuffer = device_flush_front_buffer,
  208 };
  209 
  210 static const __DRIextension *image_loader_extensions[] = {
  211    &image_loader_extension.base,
  212    &image_lookup_extension.base,
  213    &use_invalidate.base,
  214    NULL,
  215 };
  216 
  217 static const __DRIextension *swrast_loader_extensions[] = {
  218    &swrast_pbuffer_loader_extension.base,
  219    &image_lookup_extension.base,
  220    &use_invalidate.base,
  221    NULL,
  222 };
  223 
  224 static int
  225 device_get_fd(_EGLDisplay *disp, _EGLDevice *dev)
  226 {
  227 #ifdef HAVE_LIBDRM
  228    int fd = disp->Options.fd;
  229    /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
  230     * and invalid one is 0.
  231     */
  232    if (fd) {
  233       /* According to the spec - if the FD does not match the EGLDevice
  234        * behaviour is undefined.
  235        *
  236        * Add a trivial sanity check since it doesn't cost us anything.
  237        */
  238       if (dev != _eglAddDevice(fd, false))
  239          return -1;
  240 
  241       /* No EGL_EXT_output* extensions are supported, hence no master perms
  242        * are needed. Get the render one - otherwise drivers might error out.
  243        */
  244       char *node = drmGetRenderDeviceNameFromFd(fd);
  245 
  246       /* Don't close the internal fd, get render node one based on it. */
  247       fd = loader_open_device(node);
  248       free(node);
  249       return fd;
  250    }
  251    const char *node = _eglGetDRMDeviceRenderNode(dev);
  252    return loader_open_device(node);
  253 #else
  254    _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet using a HW device");
  255    return -1;
  256 #endif
  257 }
  258 
  259 static bool
  260 device_probe_device(_EGLDisplay *disp)
  261 {
  262    struct dri2_egl_display *dri2_dpy = disp->DriverData;
  263 
  264    if (disp->Options.ForceSoftware)
  265       _eglLog(_EGL_WARNING, "Not allowed to force software rendering when "
  266                             "API explicitly selects a hardware device.");
  267    dri2_dpy->fd = device_get_fd(disp, disp->Device);
  268    if (dri2_dpy->fd < 0)
  269       return false;
  270 
  271    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
  272    if (!dri2_dpy->driver_name)
  273       goto err_name;
  274 
  275    if (!dri2_load_driver_dri3(disp))
  276       goto err_load;
  277 
  278    dri2_dpy->loader_extensions = image_loader_extensions;
  279    return true;
  280 
  281 err_load:
  282    free(dri2_dpy->driver_name);
  283    dri2_dpy->driver_name = NULL;
  284 
  285 err_name:
  286    close(dri2_dpy->fd);
  287    dri2_dpy->fd = -1;
  288    return false;
  289 
  290 }
  291 
  292 static bool
  293 device_probe_device_sw(_EGLDisplay *disp)
  294 {
  295    struct dri2_egl_display *dri2_dpy = disp->DriverData;
  296 
  297    dri2_dpy->fd = -1;
  298    dri2_dpy->driver_name = strdup("swrast");
  299    if (!dri2_dpy->driver_name)
  300       return false;
  301 
  302    /* HACK: should be driver_swrast_null */
  303    if (!dri2_load_driver_swrast(disp)) {
  304       free(dri2_dpy->driver_name);
  305       dri2_dpy->driver_name = NULL;
  306       return false;
  307    }
  308 
  309    dri2_dpy->loader_extensions = swrast_loader_extensions;
  310    return true;
  311 }
  312 
  313 EGLBoolean
  314 dri2_initialize_device(_EGLDriver *drv, _EGLDisplay *disp)
  315 {
  316    _EGLDevice *dev;
  317    struct dri2_egl_display *dri2_dpy;
  318    const char* err;
  319 
  320    dri2_dpy = calloc(1, sizeof *dri2_dpy);
  321    if (!dri2_dpy)
  322       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
  323 
  324    /* Extension requires a PlatformDisplay - the EGLDevice. */
  325    dev = disp->PlatformDisplay;
  326 
  327    dri2_dpy->fd = -1;
  328    disp->Device = dev;
  329    disp->DriverData = (void *) dri2_dpy;
  330    err = "DRI2: failed to load driver";
  331    if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM)) {
  332       if (!device_probe_device(disp))
  333          goto cleanup;
  334    } else if (_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)) {
  335       if (!device_probe_device_sw(disp))
  336          goto cleanup;
  337    } else {
  338       _eglLog(_EGL_FATAL, "Driver bug: exposed device is neither DRM nor SOFTWARE one");
  339       return EGL_FALSE;
  340    }
  341 
  342    if (!dri2_create_screen(disp)) {
  343       err = "DRI2: failed to create screen";
  344       goto cleanup;
  345    }
  346 
  347    if (!dri2_setup_extensions(disp)) {
  348       err = "DRI2: failed to find required DRI extensions";
  349       goto cleanup;
  350    }
  351 
  352    dri2_setup_screen(disp);
  353 
  354    if (!dri2_add_pbuffer_configs_for_visuals(drv, disp)) {
  355       err = "DRI2: failed to add configs";
  356       goto cleanup;
  357    }
  358 
  359    /* Fill vtbl last to prevent accidentally calling virtual function during
  360     * initialization.
  361     */
  362    dri2_dpy->vtbl = &dri2_device_display_vtbl;
  363 
  364    return EGL_TRUE;
  365 
  366 cleanup:
  367    dri2_display_destroy(disp);
  368    return _eglError(EGL_NOT_INITIALIZED, err);
  369 }