/* * Copyright © 2013 Keith Packard * * 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 "dri3_priv.h" #include #include #include #include #include #include int dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd) { dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; if (info == NULL) return BadMatch; if (info->version >= 1 && info->open_client != NULL) return (*info->open_client) (client, screen, provider, fd); if (info->open != NULL) return (*info->open) (screen, provider, fd); return BadMatch; } int dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, const int *fds, CARD16 width, CARD16 height, const CARD32 *strides, const CARD32 *offsets, CARD8 depth, CARD8 bpp, CARD64 modifier) { dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; PixmapPtr pixmap; if (!info) return BadImplementation; if (info->version >= 2 && info->pixmap_from_fds != NULL) { pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height, strides, offsets, depth, bpp, modifier); } else if (info->pixmap_from_fd != NULL && num_fds == 1) { pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height, strides[0], depth, bpp); } else { return BadImplementation; } if (!pixmap) return BadAlloc; *ppixmap = pixmap; return Success; } int dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds, uint32_t *strides, uint32_t *offsets, uint64_t *modifier) { ScreenPtr screen = pixmap->drawable.pScreen; dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; if (!info) return 0; if (info->version >= 2 && info->fds_from_pixmap != NULL) { return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets, modifier); } else if (info->fd_from_pixmap != NULL) { CARD16 stride; CARD32 size; fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size); if (fds[0] < 0) return 0; strides[0] = stride; offsets[0] = 0; *modifier = DRM_FORMAT_MOD_INVALID; return 1; } else { return 0; } } int dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) { ScreenPtr screen = pixmap->drawable.pScreen; dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; uint32_t strides[4]; uint32_t offsets[4]; uint64_t modifier; int fds[4]; int num_fds; if (!info) return -1; /* Preferentially use the old interface, allowing the implementation to * ensure the buffer is in a single-plane format which doesn't need * modifiers. */ if (info->fd_from_pixmap != NULL) return (*info->fd_from_pixmap)(screen, pixmap, stride, size); if (info->version < 2 || info->fds_from_pixmap == NULL) return -1; /* If using the new interface, make sure that it's a single plane starting * at 0 within the BO. We don't check the modifier, as the client may * have an auxiliary mechanism for determining the modifier itself. */ num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets, &modifier); if (num_fds != 1 || offsets[0] != 0) { int i; for (i = 0; i < num_fds; i++) close(fds[i]); return -1; } *stride = strides[0]; *size = size[0]; return fds[0]; } static int cache_formats_and_modifiers(ScreenPtr screen) { dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; CARD32 num_formats; CARD32 *formats; uint32_t num_modifiers; uint64_t *modifiers; int i; if (ds->formats_cached) return Success; if (!info) return BadImplementation; if (info->version < 2 || !info->get_formats || !info->get_modifiers) { ds->formats = NULL; ds->num_formats = 0; ds->formats_cached = TRUE; return Success; } if (!info->get_formats(screen, &num_formats, &formats)) return BadAlloc; if (!num_formats) { ds->num_formats = 0; ds->formats_cached = TRUE; return Success; } ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec)); if (!ds->formats) { free(formats); return BadAlloc; } for (i = 0; i < num_formats; i++) { dri3_dmabuf_format_ptr iter = &ds->formats[i]; if (!info->get_modifiers(screen, formats[i], &num_modifiers, &modifiers)) continue; if (!num_modifiers) continue; iter->format = formats[i]; iter->num_modifiers = num_modifiers; iter->modifiers = modifiers; } ds->num_formats = i; ds->formats_cached = TRUE; free(formats); return Success; } int dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, CARD8 depth, CARD8 bpp, CARD32 *num_drawable_modifiers, CARD64 **drawable_modifiers, CARD32 *num_screen_modifiers, CARD64 **screen_modifiers) { dri3_screen_priv_ptr ds = dri3_screen_priv(screen); const dri3_screen_info_rec *info = ds->info; int i; int ret; uint32_t num_drawable_mods; uint64_t *drawable_mods; CARD64 *screen_mods = NULL; CARD32 format; dri3_dmabuf_format_ptr screen_format = NULL; ret = cache_formats_and_modifiers(screen); if (ret != Success) return ret; format = drm_format_for_depth(depth, bpp); if (format == 0) return BadValue; /* Find screen-global modifiers from cache */ for (i = 0; i < ds->num_formats; i++) { if (ds->formats[i].format == format) { screen_format = &ds->formats[i]; break; } } if (screen_format == NULL) return BadMatch; if (screen_format->num_modifiers == 0) { *num_screen_modifiers = 0; *num_drawable_modifiers = 0; return Success; } /* copy the screen mods so we can return an owned allocation */ screen_mods = XNFalloc(screen_format->num_modifiers * sizeof(CARD64)); memcpy(screen_mods, screen_format->modifiers, screen_format->num_modifiers * sizeof(CARD64)); if (!info->get_drawable_modifiers || !info->get_drawable_modifiers(drawable, format, &num_drawable_mods, &drawable_mods)) { num_drawable_mods = 0; drawable_mods = NULL; } *num_drawable_modifiers = num_drawable_mods; *drawable_modifiers = drawable_mods; *num_screen_modifiers = screen_format->num_modifiers; *screen_modifiers = screen_mods; return Success; } int dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd) { const dri3_screen_info_rec *info = dri3_screen_priv(screen)->info; struct dri3_syncobj *syncobj = NULL; if (info->version < 4 || !info->import_syncobj) return BadImplementation; syncobj = info->import_syncobj(client, screen, id, fd); close(fd); if (!syncobj) return BadAlloc; if (!AddResource(id, dri3_syncobj_type, syncobj)) return BadAlloc; return Success; }