diff --git a/hw/xfree86/drivers/modesetting/dri3.c b/hw/xfree86/drivers/modesetting/dri3.c new file mode 100644 index 0000000000000000000000000000000000000000..d2d4f1a4250ce1739aab20c45d3eace0aa552b80 --- /dev/null +++ b/hw/xfree86/drivers/modesetting/dri3.c @@ -0,0 +1,768 @@ +/* + * Copyright © 2010 Intel Corporation. + * Copyright @ 2022 Raspberry Pi Ltd + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including + * the next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Zhigang Gong + * Christopher Michael + * Juan A. Suarez + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#include "xf86.h" +#include "driver.h" +#include "dri3.h" +#include +#include +#include +#include +#include +#include +#include + +#ifdef MS_DRI3 +static Bool ms_dri3_modifiers_get(ScreenPtr screen, uint32_t format, uint32_t *num, uint64_t **modifiers); + +static void * +ms_dri3_pixmap_map_bo(msPixmapPrivPtr ppriv, struct gbm_bo *bo) +{ + void *baddr; + uint32_t bstride, bw, bh; + + bw = gbm_bo_get_width(bo); + bh = gbm_bo_get_height(bo); + baddr = gbm_bo_map(bo, 0, 0, bw, bh, GBM_BO_TRANSFER_READ_WRITE, + &bstride, &ppriv->bo_map); + if (baddr == MAP_FAILED) { + xf86DrvMsg(-1, X_ERROR, "Failed to map bo: %s\n", strerror(errno)); + ppriv->bo = NULL; + gbm_bo_destroy(bo); + return NULL; + } + + return baddr; +} + +static Bool +ms_dri3_pixmap_make_exportable(PixmapPtr pixmap, Bool mods) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr pixmap_priv, exported_priv; + uint32_t format = GBM_FORMAT_ARGB8888; + struct gbm_bo *bo = NULL; + PixmapPtr exported; + void *baddr; + GCPtr sgc; + + pixmap_priv = msGetPixmapPriv(&ms->drmmode, pixmap); + + if (pixmap_priv->bo && + (mods || !pixmap_priv->use_modifiers)) + return TRUE; + + if (pixmap->drawable.bitsPerPixel != 32) return FALSE; + + switch (pixmap->drawable.depth) { + case 16: + format = GBM_FORMAT_RGB565; + break; + case 24: + format = GBM_FORMAT_XRGB8888; + break; + case 30: + format = GBM_FORMAT_ARGB2101010; + break; + default: + format = GBM_FORMAT_ARGB8888; + break; + } + + exported = fbCreatePixmap(screen, 0, 0, pixmap->drawable.depth, 0); + exported_priv = msGetPixmapPriv(&ms->drmmode, exported); + + if (mods) { + uint32_t num; + uint64_t *modifiers = NULL; + + ms_dri3_modifiers_get(screen, format, &num, &modifiers); + + bo = gbm_bo_create_with_modifiers(ms->drmmode.gbm, + pixmap->drawable.width, + pixmap->drawable.height, + format, modifiers, num); + if (bo) + exported_priv->use_modifiers = TRUE; + free(modifiers); + } + + if (!bo) { + uint32_t flags = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT; + + if (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED) + flags |= GBM_BO_USE_LINEAR; + + bo = gbm_bo_create(ms->drmmode.gbm, pixmap->drawable.width, + pixmap->drawable.height, format, flags); + if (!bo) goto map_fail; + } + + exported_priv->bo = bo; + + baddr = ms_dri3_pixmap_map_bo(exported_priv, bo); + if (!baddr) goto map_fail; + + screen->ModifyPixmapHeader(exported, pixmap->drawable.width, + pixmap->drawable.height, 0, 0, + gbm_bo_get_stride(bo), baddr); + + sgc = GetScratchGC(pixmap->drawable.depth, screen); + ValidateGC(&pixmap->drawable, sgc); + sgc->ops->CopyArea(&pixmap->drawable, &exported->drawable, sgc, 0, 0, + pixmap->drawable.width, pixmap->drawable.height, 0, 0); + FreeScratchGC(sgc); + + /* swap gbm_bo, data, etc */ + ms_dri3_buffers_exchange(pixmap, exported); + + screen->ModifyPixmapHeader(pixmap, pixmap->drawable.width, + pixmap->drawable.height, 0, 0, + exported->devKind, baddr); + + fbDestroyPixmap(exported); + return TRUE; + +map_fail: + fbDestroyPixmap(exported); + return FALSE; +} + +Bool +ms_dri3_pixmap_from_gbm_bo(PixmapPtr pixmap, struct gbm_bo *bo) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + uint32_t stride, w, h; + + w = gbm_bo_get_width(bo); + h = gbm_bo_get_height(bo); + stride = gbm_bo_get_stride(bo); + + screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL); + return TRUE; +} + +Bool +ms_dri3_back_pixmap_from_fd(PixmapPtr pixmap, int fd, CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr ppriv; + struct gbm_import_fd_data import = { 0 }; + struct gbm_bo *bo; + void *baddr; + + if ((bpp != 32) || + !(depth == 24 || depth == 32 || depth == 30) || width == 0 || height == 0) + return FALSE; + + import.fd = fd; + import.width = width; + import.height = height; + import.stride = stride; + import.format = GBM_FORMAT_ARGB8888; + + switch (depth) { + case 16: + import.format = GBM_FORMAT_RGB565; + break; + case 24: + import.format = GBM_FORMAT_XRGB8888; + break; + case 30: + import.format = GBM_FORMAT_ARGB2101010; + break; + default: + import.format = GBM_FORMAT_ARGB8888; + break; + } + + bo = gbm_bo_import(ms->drmmode.gbm, GBM_BO_IMPORT_FD, &import, 0); + if (!bo) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to import bo: %s\n", + strerror(errno)); + return FALSE; + } + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + ppriv->bo = bo; + ppriv->use_modifiers = FALSE; + + baddr = ms_dri3_pixmap_map_bo(ppriv, bo); + if (!baddr) { + ppriv->bo = NULL; + gbm_bo_destroy(bo); + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to map bo: %s\n", + strerror(errno)); + return FALSE; + } + + screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, baddr); + + return TRUE; +} + +Bool +ms_dri3_create_back_pixmap(PixmapPtr pixmap, int handle, int stride) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + int ret, fd; + + ret = drmPrimeHandleToFD(ms->fd, handle, O_CLOEXEC | O_RDWR, &fd); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to make prime FD for handle: %d\n", handle); + return FALSE; + } + + if (!ms_dri3_back_pixmap_from_fd(pixmap, fd, pixmap->drawable.width, + pixmap->drawable.height, stride, + pixmap->drawable.depth, + pixmap->drawable.bitsPerPixel)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to make import prime FD as pixmap: %d\n", errno); + close(fd); + return FALSE; + } + + close(fd); + return TRUE; +} + +static int +ms_dri3_render_node(int fd, struct stat *st) +{ + if (fstat(fd, st)) return -1; + if (!S_ISCHR(st->st_mode)) return -1; + return (st->st_rdev & 0x80); +} + +static int +ms_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + struct stat buff; + char *dev; + int fd = -1; + + dev = drmGetDeviceNameFromFd2(ms->fd); + +# ifdef O_CLOEXEC + fd = open(dev, O_RDWR | O_CLOEXEC); +# endif + if (fd < 0) + fd = open(dev, O_RDWR); + + free(dev); + if (fd < 0) return -BadMatch; + + if (fstat(fd, &buff)) { + close(fd); + return -BadMatch; + } + + if (!ms_dri3_render_node(fd, &buff)) { + drm_magic_t magic; + + if ((drmGetMagic(fd, &magic)) || (drmAuthMagic(ms->fd, magic))) { + close(fd); + return -BadMatch; + } + } + + *out = fd; + return Success; +} + +static inline Bool +ms_dri3_find_modifier(uint64_t modifier, const uint64_t *modifiers, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + if (modifiers[i] == modifier) + return TRUE; + } + + return FALSE; +} + +static Bool +ms_dri3_formats_get(ScreenPtr screen, CARD32 *num, CARD32 **formats) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + xf86CrtcConfigPtr xcfg = XF86_CRTC_CONFIG_PTR(scrn); + modesettingPtr ms = modesettingPTR(scrn); + int c = 0, i = 0; + + *num = 0; + + if (ms->atomic_modeset || ms->kms_has_modifiers) { + for (; c < xcfg->num_crtc; c++) { + xf86CrtcPtr crtc = xcfg->crtc[c]; + drmmode_crtc_private_ptr dcrtc = crtc->driver_private; + + if (!crtc->enabled) + continue; + + if (dcrtc->num_formats == 0) + continue; + + *formats = calloc(dcrtc->num_formats, sizeof(CARD32)); + if (!*formats) + return FALSE; + + for (i = 0; i < dcrtc->num_formats; i++) + (*formats)[i] = dcrtc->formats[i].format; + + *num = dcrtc->num_formats; + break; + } + } + + return TRUE; +} + +static inline uint32_t +ms_dri3_opaque_format_get(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_ARGB8888: + return DRM_FORMAT_XRGB8888; + case DRM_FORMAT_ARGB2101010: + return DRM_FORMAT_XRGB2101010; + default: + return format; + } +} + +static Bool +ms_dri3_modifiers_get(ScreenPtr screen, uint32_t format, uint32_t *num, uint64_t **modifiers) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + + *num = 0; + *modifiers = NULL; + + if (ms->atomic_modeset || ms->kms_has_modifiers) { + xf86CrtcConfigPtr xcfg = XF86_CRTC_CONFIG_PTR(scrn); + drmmode_format_ptr dformat = NULL; + int c = 0, i = 0, j = 0; + + format = ms_dri3_opaque_format_get(format); + + for (; c < xcfg->num_crtc; c++) { + xf86CrtcPtr crtc = xcfg->crtc[c]; + drmmode_crtc_private_ptr dcrtc = crtc->driver_private; + + if (!crtc->enabled) + continue; + + if (dcrtc->num_formats == 0) + continue; + + for (i = 0; i < dcrtc->num_formats; i++) { + if ((dcrtc->formats[i].format == format) && + (ms_dri3_find_modifier(DRM_FORMAT_MOD_LINEAR, + dcrtc->formats[i].modifiers, + dcrtc->formats[i].num_modifiers))) { + dformat = &dcrtc->formats[i]; + for (j = 0; j < dformat->num_modifiers; j++) { + if (dformat->modifiers[j] == DRM_FORMAT_MOD_LINEAR) { + free(*modifiers); + *modifiers = calloc(1, sizeof(uint64_t)); + if (!*modifiers) return FALSE; + **modifiers = dformat->modifiers[j]; + *num = 1; + return TRUE; + } + } + } + } + } + } + + return TRUE; +} + +static Bool +ms_dri3_drawable_modifiers_get(DrawablePtr draw, uint32_t format, uint32_t *num, uint64_t **modifiers) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); + modesettingPtr ms = modesettingPTR(scrn); + + if (ms->drmmode.get_drawable_modifiers) + return ms->drmmode.get_drawable_modifiers(draw, format, num, modifiers); + + *num = 0; + *modifiers = NULL; + return TRUE; +} + +static PixmapPtr +ms_dri3_pixmap_from_fds(ScreenPtr screen, CARD8 num, const int *fds, CARD16 width, CARD16 height, const CARD32 *strides, const CARD32 *offsets, CARD8 depth, CARD8 bpp, uint64_t modifier) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + PixmapPtr pixmap; + Bool ret = FALSE; + int i; + + pixmap = fbCreatePixmap(screen, 0, 0, depth, 0); + + if (modifier != DRM_FORMAT_MOD_INVALID) { + struct gbm_import_fd_modifier_data import = {0}; + struct gbm_bo *bo; + + import.width = width; + import.height = height; + import.num_fds = num; + import.modifier = modifier; + for (i = 0; i < num; i++) { + import.fds[i] = fds[i]; + import.strides[i] = strides[i]; + import.offsets[i] = offsets[i]; + } + + switch (depth) { + case 16: + import.format = GBM_FORMAT_RGB565; + break; + case 24: + import.format = GBM_FORMAT_XRGB8888; + break; + case 30: + import.format = GBM_FORMAT_ARGB2101010; + break; + default: + import.format = GBM_FORMAT_ARGB8888; + break; + } + + bo = gbm_bo_import(ms->drmmode.gbm, GBM_BO_IMPORT_FD_MODIFIER, &import, 0); + if (bo) { + msPixmapPrivPtr ppriv; + void *baddr; + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + ppriv->bo = bo; + ppriv->use_modifiers = TRUE; + + baddr = ms_dri3_pixmap_map_bo(ppriv, bo); + if (!baddr) goto map_fail; + + screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, + strides[0], baddr); + ret = TRUE; + } + } else { + if (num == 1) + ret = ms_dri3_back_pixmap_from_fd(pixmap, fds[0], width, height, + strides[0], depth, bpp); + } + + if (!screen->SetSharedPixmapBacking(pixmap, (void *)(intptr_t)fds[0])) + ret = FALSE; + +map_fail: + if (ret == FALSE) { + fbDestroyPixmap(pixmap); + return NULL; + } + + return pixmap; +} + +static int +ms_dri3_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, uint32_t *strides, uint32_t *offsets, uint64_t *modifier) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr ppriv; + struct gbm_bo *bo; + int num = 0, i; + + if (!ms_dri3_pixmap_make_exportable(pixmap, TRUE)) + return 0; + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + + if (!ppriv->bo) + ppriv->bo = ms_dri3_gbm_bo_from_pixmap(screen, pixmap); + + bo = ppriv->bo; + if (!bo) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "ms_dri3_fds_from_pixmap: pixmap has no bo\n"); + return 0; + } + + num = gbm_bo_get_plane_count(bo); + for (i = 0; i < num; i++) { + fds[i] = gbm_bo_get_fd(bo); + strides[i] = gbm_bo_get_stride_for_plane(bo, i); + offsets[i] = gbm_bo_get_offset(bo, i); + } + *modifier = gbm_bo_get_modifier(bo); + + return num; +} + +int +ms_dri3_shareable_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, CARD16 *stride, CARD32 *size) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + unsigned ohint = pixmap->usage_hint; + msPixmapPrivPtr ppriv; + struct gbm_bo *bo; + int fd = -1; + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + if (!ppriv) return -1; + + pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED; + + if (!ppriv->bo) + ppriv->bo = ms_dri3_gbm_bo_from_pixmap(screen, pixmap); + + bo = ppriv->bo; + if (!bo) goto out; + + fd = gbm_bo_get_fd(bo); + *stride = gbm_bo_get_stride(bo); + *size = *stride * gbm_bo_get_height(bo); + +out: + pixmap->usage_hint = ohint; + return fd; +} + +struct gbm_bo * +ms_dri3_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr ppriv; + uint32_t format = GBM_FORMAT_ARGB8888; + struct gbm_bo *bo; + uint32_t num; + uint64_t *modifiers = NULL; + + if (!ms_dri3_pixmap_make_exportable(pixmap, TRUE)) return NULL; + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + if (ppriv->bo) return ppriv->bo; + + switch (pixmap->drawable.depth) { + case 16: + format = GBM_FORMAT_RGB565; + break; + case 24: + format = GBM_FORMAT_XRGB8888; + break; + case 30: + format = GBM_FORMAT_ARGB2101010; + break; + default: + format = GBM_FORMAT_ARGB8888; + break; + } + + ms_dri3_modifiers_get(screen, format, &num, &modifiers); + + bo = gbm_bo_create_with_modifiers(ms->drmmode.gbm, + pixmap->drawable.width, + pixmap->drawable.height, + format, modifiers, num); + free(modifiers); + + if (!bo) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to make GBM bo: %s\n", + strerror(errno)); + return NULL; + } + + return bo; +} + +void +ms_dri3_set_drawable_modifiers_func(ScreenPtr screen, GetDrawableModifiersFuncPtr func) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + + ms->drmmode.get_drawable_modifiers = func; +} + +Bool +ms_dri3_destroy_pixmap(PixmapPtr pixmap) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + + if (pixmap->refcnt == 1) { + msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + + if (ppriv && ppriv->bo) { + gbm_bo_unmap(ppriv->bo, ppriv->bo_map); + gbm_bo_destroy(ppriv->bo); + } + } + + fbDestroyPixmap(pixmap); + + return TRUE; +} + +static Bool +ms_dri3_flink_name_get(int fd, int handle, int *name) +{ + struct drm_gem_flink f; + + f.handle = handle; + if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &f) < 0) { + if (errno == ENODEV) { + *name = handle; + return TRUE; + } + else + return FALSE; + } + + *name = f.name; + return TRUE; +} + +static void +ms_dri3_bo_name_get(int fd, struct gbm_bo *bo, int *name) +{ + union gbm_bo_handle hdl; + + hdl = gbm_bo_get_handle(bo); + if (!ms_dri3_flink_name_get(fd, hdl.u32, name)) + *name = -1; +} + +int +ms_dri3_pixmap_name_get(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr ppriv; + struct gbm_bo *bo; + int fd = -1; + + ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + + if (!ms_dri3_pixmap_make_exportable(pixmap, TRUE)) + goto fail; + + bo = ppriv->bo; + if (!bo) goto fail; + + pixmap->devKind = gbm_bo_get_stride(bo); + ms_dri3_bo_name_get(ms->fd, bo, &fd); + *stride = pixmap->devKind; + *size = pixmap->devKind * gbm_bo_get_height(bo); + +fail: + return fd; +} + +void +ms_dri3_buffers_exchange(PixmapPtr front, PixmapPtr back) +{ + ScreenPtr screen = front->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + msPixmapPrivPtr fpriv, bpriv; + Bool tmp_mod = FALSE; + struct gbm_bo *tmp_bo = NULL; + void *tmp_map; + + fpriv = msGetPixmapPriv(&ms->drmmode, front); + bpriv = msGetPixmapPriv(&ms->drmmode, back); + + tmp_bo = bpriv->bo; + tmp_map = bpriv->bo_map; + tmp_mod = bpriv->use_modifiers; + + bpriv->bo = fpriv->bo; + bpriv->bo_map = fpriv->bo_map; + bpriv->use_modifiers = fpriv->use_modifiers; + + fpriv->bo = tmp_bo; + fpriv->bo_map = tmp_map; + fpriv->use_modifiers = tmp_mod; +} + +static dri3_screen_info_rec ms_dri3_screen_info = +{ + .version = DRI3_SCREEN_INFO_VERSION, + .open = ms_dri3_open, + .get_formats = ms_dri3_formats_get, + .get_modifiers = ms_dri3_modifiers_get, + .get_drawable_modifiers = ms_dri3_drawable_modifiers_get, + .pixmap_from_fds = ms_dri3_pixmap_from_fds, + .fds_from_pixmap = ms_dri3_fds_from_pixmap, +}; + +Bool +ms_dri3_screen_init(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + Bool ret = FALSE; + + ms->drmmode.destroy_pixmap = screen->DestroyPixmap; + screen->DestroyPixmap = ms_dri3_destroy_pixmap; + + ret = dri3_screen_init(screen, &ms_dri3_screen_info); + if (!ret) + xf86DrvMsg(-1, X_ERROR, "dri3_screen_init Failed !\n"); + + return ret; +} +#endif diff --git a/hw/xfree86/drivers/modesetting/dri3_sync.c b/hw/xfree86/drivers/modesetting/dri3_sync.c new file mode 100644 index 0000000000000000000000000000000000000000..7b83d1255e71344e5db489609baa7dcb6e3a5608 --- /dev/null +++ b/hw/xfree86/drivers/modesetting/dri3_sync.c @@ -0,0 +1,126 @@ +/* + * Copyright © 2014 Keith Packard + * Copyright @ 2022 Raspberry Pi Ltd + * + * 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. + * + * Authors: + * Christopher Michael + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#include "xf86.h" +#include "driver.h" +#include "dri3.h" +#ifdef XSYNC +# include "misync.h" +# ifdef HAVE_XSHMFENCE +# include "misyncshm.h" +# endif +# include "misyncstr.h" +# include +#endif + +#if XSYNC +static DevPrivateKeyRec dri3_sync_fence_key; + +struct dri3_sync_fence { + SyncFenceSetTriggeredFunc set_triggered; +}; + +static inline struct dri3_sync_fence * +ms_dri3_get_sync_fence(SyncFence *fence) +{ + return (struct dri3_sync_fence *)dixLookupPrivate(&fence->devPrivates, &dri3_sync_fence_key); +} + +static void +ms_dri3_sync_fence_set_triggered(SyncFence *fence) +{ + struct dri3_sync_fence *dri3_fence = ms_dri3_get_sync_fence(fence); + + fence->funcs.SetTriggered = dri3_fence->set_triggered; + fence->funcs.SetTriggered(fence); + dri3_fence->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = ms_dri3_sync_fence_set_triggered; +} + +static void +ms_dri3_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool triggered) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + SyncScreenFuncsPtr scrn_funcs = miSyncGetScreenFuncs(screen); + struct dri3_sync_fence *dri3_fence = ms_dri3_get_sync_fence(fence); + + scrn_funcs->CreateFence = ms->drmmode.sync_funcs.CreateFence; + scrn_funcs->CreateFence(screen, fence, triggered); + ms->drmmode.sync_funcs.CreateFence = scrn_funcs->CreateFence; + scrn_funcs->CreateFence = ms_dri3_sync_create_fence; + + dri3_fence->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = ms_dri3_sync_fence_set_triggered; +} +#endif + +Bool +ms_dri3_sync_init(ScreenPtr screen) +{ +#if XSYNC + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + SyncScreenFuncsPtr scrn_funcs; + + if (!dixPrivateKeyRegistered(&dri3_sync_fence_key)) { + if (!dixRegisterPrivateKey(&dri3_sync_fence_key, PRIVATE_SYNC_FENCE, + sizeof(struct dri3_sync_fence))) + return FALSE; + } + +#ifdef HAVE_XSHMFENCE + if (!miSyncShmScreenInit(screen)) + return FALSE; +#else + if (!miSyncSetup(screen)) + return FALSE; +#endif + + scrn_funcs = miSyncGetScreenFuncs(screen); + ms->drmmode.sync_funcs.CreateFence = scrn_funcs->CreateFence; + scrn_funcs->CreateFence = ms_dri3_sync_create_fence; +#endif + + return TRUE; +} + +void +ms_dri3_sync_close(ScreenPtr screen) +{ +#if XSYNC + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + SyncScreenFuncsPtr scrn_funcs = miSyncGetScreenFuncs(screen); + + if (scrn_funcs) + scrn_funcs->CreateFence = ms->drmmode.sync_funcs.CreateFence; +#endif +} diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index fe3315a9c49cfdb545f062e77db46fc2e3dcc42e..810238ed6decde10248d4942c17ac656ad315c11 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -255,7 +255,7 @@ check_outputs(int fd, int *count) *count = res->count_connectors; ret = res->count_connectors > 0; -#if defined(GLAMOR_HAS_GBM_LINEAR) +#if defined(GLAMOR_HAS_GBM_LINEAR) || defined(MS_DRI3) if (ret == FALSE) { uint64_t value = 0; if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0 && @@ -1000,6 +1000,38 @@ try_enable_glamor(ScrnInfoPtr pScrn) #endif } +static void +try_enable_dri3(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + const char *accel_method_str = xf86GetOptValString(ms->drmmode.Options, + OPTION_ACCEL_METHOD); + Bool do_dri3 = FALSE; + + ms->drmmode.dri3_enabled = FALSE; + + do_dri3 = (!accel_method_str || + strcmp(accel_method_str, "msdri3") == 0); + + if (!do_dri3) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI3 disabled\n"); + return; + } + +#ifdef MS_DRI3 + ms->drmmode.gbm = gbm_create_device(ms->fd); + if (ms->drmmode.gbm) { + ms->drmmode.dri3_enabled = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DRI3 initialized\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DRI3 initialization failed\n"); + } +#else + if (do_dri3) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No DRI3 support in the X Server\n"); +#endif +} + static Bool msShouldDoubleShadow(ScrnInfoPtr pScrn, modesettingPtr ms) { @@ -1209,8 +1241,10 @@ PreInit(ScrnInfoPtr pScrn, int flags) } try_enable_glamor(pScrn); + if (!ms->drmmode.glamor) + try_enable_dri3(pScrn); - if (!ms->drmmode.glamor) { + if (!ms->drmmode.glamor && !ms->drmmode.dri3_enabled) { Bool prefer_shadow = TRUE; if (ms->drmmode.force_24_32) { @@ -1257,11 +1291,12 @@ PreInit(ScrnInfoPtr pScrn, int flags) if (ret == 0) { if (connector_count && (value & DRM_PRIME_CAP_IMPORT)) { pScrn->capabilities |= RR_Capability_SinkOutput; - if (ms->drmmode.glamor) + if (ms->drmmode.glamor || ms->drmmode.dri3_enabled) pScrn->capabilities |= RR_Capability_SinkOffload; } -#ifdef GLAMOR_HAS_GBM_LINEAR - if (value & DRM_PRIME_CAP_EXPORT && ms->drmmode.glamor) +#if defined(GLAMOR_HAS_GBM_LINEAR) || defined(MS_DRI3) + if (value & DRM_PRIME_CAP_EXPORT && + (ms->drmmode.glamor || ms->drmmode.dri3_enabled)) pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload; #endif } @@ -1283,8 +1318,11 @@ PreInit(ScrnInfoPtr pScrn, int flags) ms->kms_has_modifiers = FALSE; ret = drmGetCap(ms->fd, DRM_CAP_ADDFB2_MODIFIERS, &value); - if (ret == 0 && value != 0) - ms->kms_has_modifiers = TRUE; + if (ret == 0 && value != 0) { + if (!ms->drmmode.glamor && ms->drmmode.dri3_enabled) + ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + ms->kms_has_modifiers = TRUE; + } if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n"); @@ -1600,7 +1638,7 @@ CreateScreenResources(ScreenPtr pScreen) if (!ms->drmmode.sw_cursor) drmmode_map_cursor_bos(pScrn, &ms->drmmode); - if (!ms->drmmode.gbm) { + if (!ms->drmmode.gbm || ms->drmmode.dri3_enabled) { pixels = drmmode_map_front_bo(&ms->drmmode); if (!pixels) return FALSE; @@ -1665,14 +1703,22 @@ CreateScreenResources(ScreenPtr pScreen) static Bool msSharePixmapBacking(PixmapPtr ppix, ScreenPtr secondary, void **handle) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(ppix->drawable.pScreen)); - int ret; + int ret = -1; CARD16 stride; CARD32 size; - ret = ms->glamor.shareable_fd_from_pixmap(ppix->drawable.pScreen, ppix, + + if (ms->drmmode.glamor) + ret = ms->glamor.shareable_fd_from_pixmap(ppix->drawable.pScreen, ppix, + &stride, &size); +# ifdef MS_DRI3 + else if (ms->drmmode.dri3_enabled) + ret = ms_dri3_shareable_fd_from_pixmap(ppix->drawable.pScreen, ppix, &stride, &size); +# endif + if (ret == -1) return FALSE; @@ -1685,11 +1731,11 @@ msSharePixmapBacking(PixmapPtr ppix, ScreenPtr secondary, void **handle) static Bool msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) ScreenPtr screen = ppix->drawable.pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); - Bool ret; + Bool ret = FALSE; int ihandle = (int) (long) fd_handle; if (ihandle == -1) @@ -1697,12 +1743,22 @@ msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) return drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, 0, 0); if (ms->drmmode.reverse_prime_offload_mode) { - ret = ms->glamor.back_pixmap_from_fd(ppix, ihandle, + if (ms->drmmode.glamor) + ret = ms->glamor.back_pixmap_from_fd(ppix, ihandle, + ppix->drawable.width, + ppix->drawable.height, + ppix->devKind, + ppix->drawable.depth, + ppix->drawable.bitsPerPixel); +# ifdef MS_DRI3 + else if (ms->drmmode.dri3_enabled) + ret = ms_dri3_back_pixmap_from_fd(ppix, ihandle, ppix->drawable.width, ppix->drawable.height, ppix->devKind, ppix->drawable.depth, ppix->drawable.bitsPerPixel); +# endif } else { int size = ppix->devKind * ppix->drawable.height; ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size); @@ -1822,6 +1878,11 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) ms->drmmode.gbm = ms->glamor.egl_get_gbm_device(pScreen); #endif +#ifdef MS_DRI3 + if (ms->drmmode.dri3_enabled && !ms->drmmode.gbm) + ms->drmmode.gbm = gbm_create_device(ms->fd); +#endif + /* HW dependent - FIXME */ pScrn->displayWidth = pScrn->virtualX; if (!drmmode_create_initial_bos(pScrn, &ms->drmmode)) @@ -1846,8 +1907,8 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) if (!miSetPixmapDepths()) return FALSE; - if (!dixRegisterScreenSpecificPrivateKey - (pScreen, &ms->drmmode.pixmapPrivateKeyRec, PRIVATE_PIXMAP, + if (!dixRegisterPrivateKey + (&ms->drmmode.pixmapPrivateKeyRec, PRIVATE_PIXMAP, sizeof(msPixmapPrivRec))) { return FALSE; } @@ -1924,7 +1985,8 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) * later memory should be bound when allocating, e.g rotate_mem */ pScrn->vtSema = TRUE; - if (serverGeneration == 1 && bgNoneRoot && ms->drmmode.glamor) { + if (serverGeneration == 1 && bgNoneRoot && + (ms->drmmode.glamor || ms->drmmode.dri3_enabled)) { ms->CreateWindow = pScreen->CreateWindow; pScreen->CreateWindow = CreateWindow_oneshot; } @@ -1987,43 +2049,59 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize the DRI2 extension.\n"); } + } +#endif - /* enable reverse prime if we are a GPU screen, and accelerated, and not - * i915, evdi or udl. i915 is happy scanning out from sysmem. - * evdi and udl are virtual drivers scanning out from sysmem - * backed dumb buffers. - */ - if (pScreen->isGPU) { - drmVersionPtr version; - - /* enable if we are an accelerated GPU screen */ - ms->drmmode.reverse_prime_offload_mode = TRUE; - - if ((version = drmGetVersion(ms->drmmode.fd))) { - if (!strncmp("i915", version->name, version->name_len)) { - ms->drmmode.reverse_prime_offload_mode = FALSE; - } - if (!strncmp("evdi", version->name, version->name_len)) { - ms->drmmode.reverse_prime_offload_mode = FALSE; - } - if (!strncmp("udl", version->name, version->name_len)) { - ms->drmmode.reverse_prime_offload_mode = FALSE; - } - if (!ms->drmmode.reverse_prime_offload_mode) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Disable reverse prime offload mode for %s.\n", version->name); - } - drmFreeVersion(version); - } +#ifdef MS_DRI3 + /* Note: dri3_enabled is set in try_enable_dri3 function first. We reuse + * the variable here checking the return of ms_dri3_screen_init so that we + * can know if DRI3 is actually setup */ + if (ms->drmmode.dri3_enabled) { + if (!(ms->drmmode.dri3_enabled = ms_dri3_screen_init(pScreen))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize the DRI3 extension.\n"); + } + if (!ms_dri3_sync_init(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize the Sync extension.\n"); } } #endif + + /* enable reverse prime if we are a GPU screen, and accelerated, and not + * i915, evdi or udl. i915 is happy scanning out from sysmem. + * evdi and udl are virtual drivers scanning out from sysmem + * backed dumb buffers. + */ + if (pScreen->isGPU) { + drmVersionPtr version; + + /* enable if we are an accelerated GPU screen */ + ms->drmmode.reverse_prime_offload_mode = TRUE; + + if ((version = drmGetVersion(ms->drmmode.fd))) { + if (!strncmp("i915", version->name, version->name_len)) { + ms->drmmode.reverse_prime_offload_mode = FALSE; + } + if (!strncmp("evdi", version->name, version->name_len)) { + ms->drmmode.reverse_prime_offload_mode = FALSE; + } + if (!strncmp("udl", version->name, version->name_len)) { + ms->drmmode.reverse_prime_offload_mode = FALSE; + } + if (!ms->drmmode.reverse_prime_offload_mode) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Disable reverse prime offload mode for %s.\n", version->name); + } + drmFreeVersion(version); + } + } + if (!(ms->drmmode.present_enable = ms_present_screen_init(pScreen))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize the Present extension.\n"); } - pScrn->vtSema = TRUE; if (ms->vrr_support) { @@ -2125,6 +2203,11 @@ CloseScreen(ScreenPtr pScreen) /* Clear mask of assigned crtc's in this generation */ ms_ent->assigned_crtcs = 0; +#ifdef MS_DRI3 + if (ms->drmmode.dri3_enabled) + ms_dri3_sync_close(pScreen); +#endif + #ifdef GLAMOR_HAS_GBM if (ms->drmmode.dri2_enable) { ms_dri2_close_screen(pScreen); @@ -2163,6 +2246,11 @@ CloseScreen(ScreenPtr pScreen) LeaveVT(pScrn); } +#ifdef MS_DRI3 + if (ms->drmmode.dri3_enabled) + pScreen->DestroyPixmap = ms->drmmode.destroy_pixmap; +#endif + pScreen->CreateScreenResources = ms->createScreenResources; pScreen->BlockHandler = ms->BlockHandler; diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 71aa8730ec2fd74bec50d2bf237b474abe5197df..c94d4ff6ce9b558eb1bb59beadf6287b7408e9d6 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -36,10 +36,14 @@ #include #include #include + #ifdef GLAMOR_HAS_GBM -#define GLAMOR_FOR_XORG 1 -#include "glamor.h" -#include +# define GLAMOR_FOR_XORG 1 +# include "glamor.h" +#endif + +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) +# include #endif #include "drmmode_display.h" @@ -220,7 +224,22 @@ void ms_vblank_close_screen(ScreenPtr screen); Bool ms_present_screen_init(ScreenPtr screen); -#ifdef GLAMOR_HAS_GBM +#ifdef MS_DRI3 +Bool ms_dri3_screen_init(ScreenPtr screen); +Bool ms_dri3_create_back_pixmap(PixmapPtr pixmap, int handle, int stride); +Bool ms_dri3_pixmap_from_gbm_bo(PixmapPtr pixmap, struct gbm_bo *bo); +int ms_dri3_shareable_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, CARD16 *stride, CARD32 *size); +Bool ms_dri3_sync_init(ScreenPtr screen); +void ms_dri3_sync_close(ScreenPtr screen); +struct gbm_bo *ms_dri3_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap); +Bool ms_dri3_destroy_pixmap(PixmapPtr pixmap); +void ms_dri3_set_drawable_modifiers_func(ScreenPtr screen, GetDrawableModifiersFuncPtr func); +Bool ms_dri3_back_pixmap_from_fd(PixmapPtr pixmap, int fd, CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp); +int ms_dri3_pixmap_name_get(PixmapPtr pixmap, CARD16 *stride, CARD32 *size); +void ms_dri3_buffers_exchange(PixmapPtr front, PixmapPtr back); +#endif + +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) typedef void (*ms_pageflip_handler_proc)(modesettingPtr ms, uint64_t frame, diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 65e8e63353a04693de76fba1c808c8bfcfd63676..4f538641808a51f543bec5c00282356300b8413a 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -162,7 +162,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier return TRUE; } -#ifdef GBM_BO_WITH_MODIFIERS +#if defined(GBM_BO_WITH_MODIFIERS) || defined(MS_DRI3) static uint32_t get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers, Bool enabled_crtc_only, Bool exclude_multiplane) @@ -959,8 +959,8 @@ drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo) { int ret; -#ifdef GLAMOR_HAS_GBM - if (bo->gbm) { +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) + if (bo->gbm && drmmode->glamor) { gbm_bo_destroy(bo->gbm); bo->gbm = NULL; } @@ -978,7 +978,7 @@ drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo) uint32_t drmmode_bo_get_pitch(drmmode_bo *bo) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) if (bo->gbm) return gbm_bo_get_stride(bo->gbm); #endif @@ -989,7 +989,7 @@ drmmode_bo_get_pitch(drmmode_bo *bo) static Bool drmmode_bo_has_bo(drmmode_bo *bo) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) if (bo->gbm) return TRUE; #endif @@ -1000,7 +1000,7 @@ drmmode_bo_has_bo(drmmode_bo *bo) uint32_t drmmode_bo_get_handle(drmmode_bo *bo) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) if (bo->gbm) return gbm_bo_get_handle(bo->gbm).u32; #endif @@ -1013,7 +1013,7 @@ drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo) { int ret; -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) if (bo->gbm) return NULL; #endif @@ -1032,7 +1032,7 @@ int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo, uint32_t *fb_id) { -#ifdef GBM_BO_WITH_MODIFIERS +#if defined(GBM_BO_WITH_MODIFIERS) || defined(MS_DRI3) modesettingPtr ms = modesettingPTR(drmmode->scrn); if (bo->gbm && ms->kms_has_modifiers && gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) { @@ -1076,17 +1076,19 @@ drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo, static Bool drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, - unsigned width, unsigned height, unsigned bpp) + unsigned width, unsigned height, unsigned bpp, Bool use_dumb) { bo->width = width; bo->height = height; -#ifdef GLAMOR_HAS_GBM - if (drmmode->glamor) { -#ifdef GBM_BO_WITH_MODIFIERS + if (use_dumb) goto create_dumb; + +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) + if (drmmode->gbm) { +# if defined(GBM_BO_WITH_MODIFIERS) || defined(MS_DRI3) uint32_t num_modifiers; uint64_t *modifiers = NULL; -#endif +# endif uint32_t format; switch (drmmode->scrn->depth) { @@ -1104,7 +1106,7 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, break; } -#ifdef GBM_BO_WITH_MODIFIERS +# if defined(GBM_BO_WITH_MODIFIERS) || defined(MS_DRI3) num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers, FALSE, TRUE); if (num_modifiers > 0 && @@ -1118,7 +1120,7 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, return TRUE; } } -#endif +# endif bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); @@ -1127,6 +1129,7 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, } #endif +create_dumb: bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp); return bo->dumb != NULL; } @@ -1455,7 +1458,7 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) } } -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) static PixmapPtr create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id) { @@ -1463,7 +1466,7 @@ create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id) drmModeFBPtr fbcon; ScreenPtr pScreen = xf86ScrnToScreen(pScrn); modesettingPtr ms = modesettingPTR(pScrn); - Bool ret; + Bool ret = FALSE; if (pixmap) return pixmap; @@ -1483,8 +1486,14 @@ create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id) if (!pixmap) goto out_free_fb; - ret = ms->glamor.egl_create_textured_pixmap(pixmap, fbcon->handle, - fbcon->pitch); + if (drmmode->glamor) + ret = ms->glamor.egl_create_textured_pixmap(pixmap, fbcon->handle, + fbcon->pitch); +# ifdef MS_DRI3 + else if (drmmode->dri3_enabled) + ret = ms_dri3_create_back_pixmap(pixmap, fbcon->handle, fbcon->pitch); +# endif + if (!ret) { FreePixmap(pixmap); pixmap = NULL; @@ -1500,7 +1509,7 @@ out_free_fb: void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); ScreenPtr pScreen = xf86ScrnToScreen(pScrn); PixmapPtr src, dst; @@ -1914,6 +1923,7 @@ drmmode_clear_pixmap(PixmapPtr pixmap) { ScreenPtr screen = pixmap->drawable.pScreen; GCPtr gc; + #ifdef GLAMOR_HAS_GBM modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen)); @@ -1938,7 +1948,7 @@ drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height) int ret; if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo, - width, height, drmmode->kbpp)) { + width, height, drmmode->kbpp, FALSE)) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "Couldn't allocate shadow memory for rotated CRTC\n"); return NULL; @@ -1953,7 +1963,7 @@ drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height) return NULL; } -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) if (drmmode->gbm) return drmmode_crtc->rotate_bo.gbm; #endif @@ -3284,7 +3294,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r /* work out the possible clones later */ output->possible_clones = 0; - if (ms->atomic_modeset) { + if (ms->atomic_modeset || ms->kms_has_modifiers) { if (!drmmode_prop_info_copy(drmmode_output->props_connector, connector_props, DRMMODE_CONNECTOR__COUNT, 0)) { @@ -3389,18 +3399,28 @@ drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_re static Bool drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) ScrnInfoPtr scrn = drmmode->scrn; modesettingPtr ms = modesettingPTR(scrn); - if (!drmmode->glamor) + if (!drmmode->glamor && !drmmode->dri3_enabled) return TRUE; - if (!ms->glamor.egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm, - bo->used_modifiers)) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n"); - return FALSE; - } + if (drmmode->glamor) { + if (!ms->glamor.egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm, + bo->used_modifiers)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n"); + return FALSE; + } + } +# ifdef MS_DRI3 + else if (drmmode->dri3_enabled && bo->gbm) { + if (!ms_dri3_pixmap_from_gbm_bo(pixmap, bo->gbm)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n"); + return FALSE; + } + } +# endif #endif return TRUE; @@ -3447,7 +3467,7 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) drmmode->fb_id = 0; if (!drmmode_create_bo(drmmode, &drmmode->front_bo, - width, height, drmmode->kbpp)) + width, height, drmmode->kbpp, drmmode->dri3_enabled)) goto fail; pitch = drmmode_bo_get_pitch(&drmmode->front_bo); @@ -3456,7 +3476,7 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) scrn->virtualY = height; scrn->displayWidth = pitch / kcpp; - if (!drmmode->gbm) { + if (!drmmode->gbm || drmmode->dri3_enabled) { new_pixels = drmmode_map_front_bo(drmmode); if (!new_pixels) goto fail; @@ -3718,7 +3738,7 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) Bool drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) { -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) ScreenPtr pScreen = xf86ScrnToScreen(pScrn); modesettingPtr ms = modesettingPTR(pScrn); @@ -3726,10 +3746,15 @@ drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) if (!ms->glamor.init(pScreen, GLAMOR_USE_EGL_SCREEN)) { return FALSE; } -#ifdef GBM_BO_WITH_MODIFIERS +# ifdef GBM_BO_WITH_MODIFIERS ms->glamor.set_drawable_modifiers_func(pScreen, get_drawable_modifiers); -#endif +# endif } +# ifdef MS_DRI3 + else if (drmmode->dri3_enabled) + ms_dri3_set_drawable_modifiers_func(pScreen, get_drawable_modifiers); +# endif + #endif return TRUE; @@ -4169,7 +4194,8 @@ drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) width = pScrn->virtualX; height = pScrn->virtualY; - if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp)) + if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, + bpp, drmmode->dri3_enabled)) return FALSE; pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp; diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 2a9a915293a5ab092bd4de9749b795228a505b6f..af71b6cb664ac8ce7060f9e63b8a030d6289078e 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -36,6 +36,16 @@ #include "dumb_bo.h" +#ifdef MS_DRI3 +typedef Bool (*GetDrawableModifiersFuncPtr) (DrawablePtr draw, uint32_t format, uint32_t *num_modifiers, uint64_t **modifiers); +# ifdef XSYNC +# include "misync.h" +# ifdef HAVE_XSHMFENCE +# include "misyncshm.h" +# endif +# endif +#endif + struct gbm_device; enum drmmode_plane_property { @@ -79,7 +89,7 @@ typedef struct { uint32_t width; uint32_t height; struct dumb_bo *dumb; -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) Bool used_modifiers; struct gbm_bo *gbm; #endif @@ -136,6 +146,17 @@ typedef struct { Bool dri2_enable; Bool present_enable; + /* bool flag to indicate if modesetting driver has enabled DRI3 support. + * Note: This only makes sense if glamor is disabled */ + Bool dri3_enabled; +#ifdef MS_DRI3 + DestroyPixmapProcPtr destroy_pixmap; + GetDrawableModifiersFuncPtr get_drawable_modifiers; +# ifdef XSYNC + SyncScreenFuncsRec sync_funcs; +# endif +#endif + uint32_t vrr_prop_id; Bool use_ctm; } drmmode_rec, *drmmode_ptr; @@ -255,6 +276,12 @@ typedef struct _msPixmapPriv { PixmapDirtyUpdatePtr dirty; /* cached dirty ent to avoid searching list */ DrawablePtr secondary_src; /* if we exported shared pixmap, dirty tracking src */ Bool notify_on_damage; /* if sink has requested damage notification */ + +#ifdef MS_DRI3 + struct gbm_bo *bo; + void *bo_map; + Bool use_modifiers; +#endif } msPixmapPrivRec, *msPixmapPrivPtr; #define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec)) diff --git a/hw/xfree86/drivers/modesetting/meson.build b/hw/xfree86/drivers/modesetting/meson.build index 02852a7165f87413e52e34f429eabee40787a2f4..32e7edc93d16d5093adb9d8de43dd4f11c457e94 100644 --- a/hw/xfree86/drivers/modesetting/meson.build +++ b/hw/xfree86/drivers/modesetting/meson.build @@ -1,4 +1,6 @@ modesetting_srcs = [ + 'dri3_sync.c', + 'dri3.c', 'dri2.c', 'driver.c', 'drmmode_display.c', @@ -20,6 +22,7 @@ shared_module( udev_dep, libdrm_dep, gbm_dep, + epoxy_dep, ], install: true, diff --git a/hw/xfree86/drivers/modesetting/modesetting.man b/hw/xfree86/drivers/modesetting/modesetting.man index 71790011ec93f903a7b689980578086de144e70b..d30b55adb5bee8b134414ad936dd5b8294c7c405 100644 --- a/hw/xfree86/drivers/modesetting/modesetting.man +++ b/hw/xfree86/drivers/modesetting/modesetting.man @@ -17,7 +17,7 @@ modesetting \- video driver for framebuffer device is an @xservername@ driver for KMS devices. This driver supports TrueColor visuals at framebuffer depths of 15, 16, 24, and 30. RandR 1.2 is supported for multi-head configurations. Acceleration is available -through glamor for devices supporting at least OpenGL ES 2.0 or OpenGL 2.1. +through glamor or DRI3 for devices supporting at least OpenGL ES 2.0 or OpenGL 2.1. If glamor is not enabled, a shadow framebuffer is configured based on the KMS drivers' preference (unless the framebuffer is 24 bits per pixel, in which case the shadow framebuffer is always used). @@ -65,7 +65,7 @@ This defaults to enabled for ASPEED and Matrox G200 devices, and disabled otherwise. .TP .BI "Option \*qAccelMethod\*q \*q" string \*q -One of \*qglamor\*q or \*qnone\*q. Default: glamor. +One of \*qglamor\*q or \*qmsdri3\*q or \*qnone\*q. Default: glamor. .TP .BI "Option \*qPageFlip\*q \*q" boolean \*q Enable DRI3 page flipping. The default is diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c index 23ee95f9a68d96c037c33ce28e2afb7761c552bb..6acce8ab121b365d30d05eff158cbab23080996c 100644 --- a/hw/xfree86/drivers/modesetting/pageflip.c +++ b/hw/xfree86/drivers/modesetting/pageflip.c @@ -63,7 +63,7 @@ ms_flush_drm_events(ScreenPtr screen) return 1; } -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) /* * Event data for an in progress flip. @@ -305,7 +305,7 @@ ms_do_pageflip(ScreenPtr screen, ms_pageflip_abort_proc pageflip_abort, const char *log_prefix) { -#ifndef GLAMOR_HAS_GBM +#if !defined(GLAMOR_HAS_GBM) && !defined(MS_DRI3) return FALSE; #else ScrnInfoPtr scrn = xf86ScreenToScrn(screen); @@ -315,9 +315,16 @@ ms_do_pageflip(ScreenPtr screen, uint32_t flags; int i; struct ms_flipdata *flipdata; - ms->glamor.block_handler(screen); - new_front_bo.gbm = ms->glamor.gbm_bo_from_pixmap(screen, new_front); + if (ms->drmmode.glamor) { + ms->glamor.block_handler(screen); + new_front_bo.gbm = ms->glamor.gbm_bo_from_pixmap(screen, new_front); + } +# ifdef MS_DRI3 + else if (ms->drmmode.dri3_enabled) + new_front_bo.gbm = ms_dri3_gbm_bo_from_pixmap(screen, new_front); +# endif + new_front_bo.dumb = NULL; if (!new_front_bo.gbm) { diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index c3266d87116a8841ea4c9c302f43d8e706c427e6..7a7dfd5c7c7a1e7af2ef858d7411b4fad61110eb 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -185,7 +185,7 @@ ms_present_flush(WindowPtr window) #endif } -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) /** * Callback for the DRM event queue when a flip has completed on all pipes @@ -241,7 +241,7 @@ ms_present_check_unflip(RRCrtcPtr crtc, xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); int num_crtcs_on = 0; int i; - struct gbm_bo *gbm; + struct gbm_bo *gbm = NULL; if (!ms->drmmode.pageflip) return FALSE; @@ -278,16 +278,23 @@ ms_present_check_unflip(RRCrtcPtr crtc, if (!ms->drmmode.glamor) return FALSE; -#ifdef GBM_BO_WITH_MODIFIERS +# if defined(GBM_BO_WITH_MODIFIERS) || defined(MS_DRI3) /* Check if buffer format/modifier is supported by all active CRTCs */ - gbm = ms->glamor.gbm_bo_from_pixmap(screen, pixmap); + if (ms->drmmode.glamor) + gbm = ms->glamor.gbm_bo_from_pixmap(screen, pixmap); +# ifdef MS_DRI3 + else if (ms->drmmode.dri3_enabled) + gbm = ms_dri3_gbm_bo_from_pixmap(screen, pixmap); +# endif + if (gbm) { uint32_t format; uint64_t modifier; format = gbm_bo_get_format(gbm); modifier = gbm_bo_get_modifier(gbm); - gbm_bo_destroy(gbm); + if (ms->drmmode.glamor) + gbm_bo_destroy(gbm); if (!drmmode_is_format_supported(scrn, format, modifier)) { if (reason) @@ -295,7 +302,7 @@ ms_present_check_unflip(RRCrtcPtr crtc, return FALSE; } } -#endif +# endif /* Make sure there's a bo we can get to */ /* XXX: actually do this. also...is it sufficient? @@ -447,7 +454,7 @@ static present_screen_info_rec ms_present_screen_info = { .flush = ms_present_flush, .capabilities = PresentCapabilityNone, -#ifdef GLAMOR_HAS_GBM +#if defined(GLAMOR_HAS_GBM) || defined(MS_DRI3) .check_flip = NULL, .check_flip2 = ms_present_check_flip, .flip = ms_present_flip, diff --git a/include/meson.build b/include/meson.build index 6c1c1dcd4acbacbaac3b530962359b7964c852a3..dad0f4e7acaad1d0f5cecccddc49f157c2b663ed 100644 --- a/include/meson.build +++ b/include/meson.build @@ -115,6 +115,8 @@ conf_data.set('GBM_BO_WITH_MODIFIERS', build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1') ? '1' : false) conf_data.set('GBM_BO_FD_FOR_PLANE', build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 21.1') ? '1' : false) +conf_data.set('MS_DRI3', + build_ms_dri3 and gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1') ? '1' : false) conf_data.set_quoted('SERVER_MISC_CONFIG_PATH', serverconfigdir) conf_data.set_quoted('PROJECTROOT', get_option('prefix')) diff --git a/meson.build b/meson.build index 47ecb06c96099d7ba743bf5a32007a86ff440611..304613c15aa119fefeb1ad6432436316a4f6c6cb 100644 --- a/meson.build +++ b/meson.build @@ -503,7 +503,21 @@ if not libdrm_dep.found() and libdrm_required error('DRI requested, but LIBDRM not found') endif +build_ms_dri3 = false build_modesetting = libdrm_dep.found() and dri2proto_dep.found() +if build_modesetting + if build_dri3 + gbm_dep = dependency('gbm', version: '>= 17.1', required: true) + epoxy_dep = dependency('epoxy', required: true) + if not gbm_dep.found() + error('DRI3 requested, but gbm not found') + endif + if not epoxy_dep.found() + error('DRI3 requested, but epoxy not found') + endif + build_ms_dri3 = gbm_dep.found() and epoxy_dep.found() + endif +endif build_vgahw = false if get_option('vgahw') == 'auto'