dri3_screen.c revision 1b5d61b8
135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2013 Keith Packard 335c4bbdfSmrg * 435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its 535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that 635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright 735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and 835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or 935c4bbdfSmrg * publicity pertaining to distribution of the software without specific, 1035c4bbdfSmrg * written prior permission. The copyright holders make no representations 1135c4bbdfSmrg * about the suitability of this software for any purpose. It is provided "as 1235c4bbdfSmrg * is" without express or implied warranty. 1335c4bbdfSmrg * 1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2035c4bbdfSmrg * OF THIS SOFTWARE. 2135c4bbdfSmrg */ 2235c4bbdfSmrg 2335c4bbdfSmrg#ifdef HAVE_XORG_CONFIG_H 2435c4bbdfSmrg#include <xorg-config.h> 2535c4bbdfSmrg#endif 2635c4bbdfSmrg 2735c4bbdfSmrg#include "dri3_priv.h" 2835c4bbdfSmrg#include <syncsdk.h> 2935c4bbdfSmrg#include <misync.h> 3035c4bbdfSmrg#include <misyncshm.h> 3135c4bbdfSmrg#include <randrstr.h> 321b5d61b8Smrg#include <drm_fourcc.h> 331b5d61b8Smrg#include <unistd.h> 3435c4bbdfSmrg 3535c4bbdfSmrgint 3635c4bbdfSmrgdri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd) 3735c4bbdfSmrg{ 3835c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 391b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 4035c4bbdfSmrg 411b5d61b8Smrg if (info == NULL) 4235c4bbdfSmrg return BadMatch; 4335c4bbdfSmrg 4435c4bbdfSmrg if (info->version >= 1 && info->open_client != NULL) 451b5d61b8Smrg return (*info->open_client) (client, screen, provider, fd); 461b5d61b8Smrg if (info->open != NULL) 471b5d61b8Smrg return (*info->open) (screen, provider, fd); 4835c4bbdfSmrg 491b5d61b8Smrg return BadMatch; 5035c4bbdfSmrg} 5135c4bbdfSmrg 5235c4bbdfSmrgint 531b5d61b8Smrgdri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, 541b5d61b8Smrg CARD8 num_fds, const int *fds, 551b5d61b8Smrg CARD16 width, CARD16 height, 561b5d61b8Smrg const CARD32 *strides, const CARD32 *offsets, 571b5d61b8Smrg CARD8 depth, CARD8 bpp, CARD64 modifier) 5835c4bbdfSmrg{ 5935c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 601b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 6135c4bbdfSmrg PixmapPtr pixmap; 6235c4bbdfSmrg 631b5d61b8Smrg if (!info) 6435c4bbdfSmrg return BadImplementation; 6535c4bbdfSmrg 661b5d61b8Smrg if (info->version >= 2 && info->pixmap_from_fds != NULL) { 671b5d61b8Smrg pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height, 681b5d61b8Smrg strides, offsets, depth, bpp, modifier); 691b5d61b8Smrg } else if (info->pixmap_from_fd != NULL && num_fds == 1) { 701b5d61b8Smrg pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height, 711b5d61b8Smrg strides[0], depth, bpp); 721b5d61b8Smrg } else { 731b5d61b8Smrg return BadImplementation; 741b5d61b8Smrg } 751b5d61b8Smrg 7635c4bbdfSmrg if (!pixmap) 7735c4bbdfSmrg return BadAlloc; 7835c4bbdfSmrg 7935c4bbdfSmrg *ppixmap = pixmap; 8035c4bbdfSmrg return Success; 8135c4bbdfSmrg} 8235c4bbdfSmrg 8335c4bbdfSmrgint 841b5d61b8Smrgdri3_fds_from_pixmap(PixmapPtr pixmap, int *fds, 851b5d61b8Smrg uint32_t *strides, uint32_t *offsets, 861b5d61b8Smrg uint64_t *modifier) 8735c4bbdfSmrg{ 8835c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 8935c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 901b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 911b5d61b8Smrg 921b5d61b8Smrg if (!info) 931b5d61b8Smrg return 0; 941b5d61b8Smrg 951b5d61b8Smrg if (info->version >= 2 && info->fds_from_pixmap != NULL) { 961b5d61b8Smrg return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets, 971b5d61b8Smrg modifier); 981b5d61b8Smrg } else if (info->fd_from_pixmap != NULL) { 991b5d61b8Smrg CARD16 stride; 1001b5d61b8Smrg CARD32 size; 1011b5d61b8Smrg 1021b5d61b8Smrg fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size); 1031b5d61b8Smrg if (fds[0] < 0) 1041b5d61b8Smrg return 0; 1051b5d61b8Smrg 1061b5d61b8Smrg strides[0] = stride; 1071b5d61b8Smrg offsets[0] = 0; 1081b5d61b8Smrg *modifier = DRM_FORMAT_MOD_INVALID; 1091b5d61b8Smrg return 1; 1101b5d61b8Smrg } else { 1111b5d61b8Smrg return 0; 1121b5d61b8Smrg } 1131b5d61b8Smrg} 1141b5d61b8Smrg 1151b5d61b8Smrgint 1161b5d61b8Smrgdri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 1171b5d61b8Smrg{ 1181b5d61b8Smrg ScreenPtr screen = pixmap->drawable.pScreen; 1191b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 1201b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 1211b5d61b8Smrg uint32_t strides[4]; 1221b5d61b8Smrg uint32_t offsets[4]; 1231b5d61b8Smrg uint64_t modifier; 1241b5d61b8Smrg int fds[4]; 1251b5d61b8Smrg int num_fds; 1261b5d61b8Smrg 1271b5d61b8Smrg if (!info) 1281b5d61b8Smrg return -1; 1291b5d61b8Smrg 1301b5d61b8Smrg /* Preferentially use the old interface, allowing the implementation to 1311b5d61b8Smrg * ensure the buffer is in a single-plane format which doesn't need 1321b5d61b8Smrg * modifiers. */ 1331b5d61b8Smrg if (info->fd_from_pixmap != NULL) 1341b5d61b8Smrg return (*info->fd_from_pixmap)(screen, pixmap, stride, size); 1351b5d61b8Smrg 1361b5d61b8Smrg if (info->version < 2 || info->fds_from_pixmap == NULL) 1371b5d61b8Smrg return -1; 1381b5d61b8Smrg 1391b5d61b8Smrg /* If using the new interface, make sure that it's a single plane starting 1401b5d61b8Smrg * at 0 within the BO. We don't check the modifier, as the client may 1411b5d61b8Smrg * have an auxiliary mechanism for determining the modifier itself. */ 1421b5d61b8Smrg num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets, 1431b5d61b8Smrg &modifier); 1441b5d61b8Smrg if (num_fds != 1 || offsets[0] != 0) { 1451b5d61b8Smrg int i; 1461b5d61b8Smrg for (i = 0; i < num_fds; i++) 1471b5d61b8Smrg close(fds[i]); 1481b5d61b8Smrg return -1; 1491b5d61b8Smrg } 1501b5d61b8Smrg 1511b5d61b8Smrg *stride = strides[0]; 1521b5d61b8Smrg *size = size[0]; 1531b5d61b8Smrg return fds[0]; 1541b5d61b8Smrg} 1551b5d61b8Smrg 1561b5d61b8Smrgstatic int 1571b5d61b8Smrgcache_formats_and_modifiers(ScreenPtr screen) 1581b5d61b8Smrg{ 1591b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 1601b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 1611b5d61b8Smrg CARD32 num_formats; 1621b5d61b8Smrg CARD32 *formats; 1631b5d61b8Smrg uint32_t num_modifiers; 1641b5d61b8Smrg uint64_t *modifiers; 1651b5d61b8Smrg int i; 1661b5d61b8Smrg 1671b5d61b8Smrg if (ds->formats_cached) 1681b5d61b8Smrg return Success; 16935c4bbdfSmrg 1701b5d61b8Smrg if (!info) 17135c4bbdfSmrg return BadImplementation; 17235c4bbdfSmrg 1731b5d61b8Smrg if (info->version < 2 || !info->get_formats || !info->get_modifiers) { 1741b5d61b8Smrg ds->formats = NULL; 1751b5d61b8Smrg ds->num_formats = 0; 1761b5d61b8Smrg ds->formats_cached = TRUE; 1771b5d61b8Smrg return Success; 1781b5d61b8Smrg } 1791b5d61b8Smrg 1801b5d61b8Smrg if (!info->get_formats(screen, &num_formats, &formats)) 1811b5d61b8Smrg return BadAlloc; 1821b5d61b8Smrg 1831b5d61b8Smrg if (!num_formats) { 1841b5d61b8Smrg ds->num_formats = 0; 1851b5d61b8Smrg ds->formats_cached = TRUE; 1861b5d61b8Smrg return Success; 1871b5d61b8Smrg } 1881b5d61b8Smrg 1891b5d61b8Smrg ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec)); 1901b5d61b8Smrg if (!ds->formats) 19135c4bbdfSmrg return BadAlloc; 1921b5d61b8Smrg 1931b5d61b8Smrg for (i = 0; i < num_formats; i++) { 1941b5d61b8Smrg dri3_dmabuf_format_ptr iter = &ds->formats[i]; 1951b5d61b8Smrg 1961b5d61b8Smrg if (!info->get_modifiers(screen, formats[i], 1971b5d61b8Smrg &num_modifiers, 1981b5d61b8Smrg &modifiers)) 1991b5d61b8Smrg continue; 2001b5d61b8Smrg 2011b5d61b8Smrg if (!num_modifiers) 2021b5d61b8Smrg continue; 2031b5d61b8Smrg 2041b5d61b8Smrg iter->format = formats[i]; 2051b5d61b8Smrg iter->num_modifiers = num_modifiers; 2061b5d61b8Smrg iter->modifiers = modifiers; 2071b5d61b8Smrg } 2081b5d61b8Smrg 2091b5d61b8Smrg ds->num_formats = i; 2101b5d61b8Smrg ds->formats_cached = TRUE; 2111b5d61b8Smrg 21235c4bbdfSmrg return Success; 21335c4bbdfSmrg} 21435c4bbdfSmrg 2151b5d61b8Smrgint 2161b5d61b8Smrgdri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, 2171b5d61b8Smrg CARD8 depth, CARD8 bpp, 2181b5d61b8Smrg CARD32 *num_intersect_modifiers, 2191b5d61b8Smrg CARD64 **intersect_modifiers, 2201b5d61b8Smrg CARD32 *num_screen_modifiers, 2211b5d61b8Smrg CARD64 **screen_modifiers) 2221b5d61b8Smrg{ 2231b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 2241b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 2251b5d61b8Smrg int i, j; 2261b5d61b8Smrg int ret; 2271b5d61b8Smrg uint32_t num_drawable_mods; 2281b5d61b8Smrg uint64_t *drawable_mods; 2291b5d61b8Smrg CARD64 *intersect_mods = NULL; 2301b5d61b8Smrg CARD64 *screen_mods = NULL; 2311b5d61b8Smrg CARD32 format; 2321b5d61b8Smrg dri3_dmabuf_format_ptr screen_format = NULL; 2331b5d61b8Smrg 2341b5d61b8Smrg ret = cache_formats_and_modifiers(screen); 2351b5d61b8Smrg if (ret != Success) 2361b5d61b8Smrg return ret; 2371b5d61b8Smrg 2381b5d61b8Smrg format = drm_format_for_depth(depth, bpp); 2391b5d61b8Smrg if (format == 0) 2401b5d61b8Smrg return BadValue; 2411b5d61b8Smrg 2421b5d61b8Smrg /* Find screen-global modifiers from cache 2431b5d61b8Smrg */ 2441b5d61b8Smrg for (i = 0; i < ds->num_formats; i++) { 2451b5d61b8Smrg if (ds->formats[i].format == format) { 2461b5d61b8Smrg screen_format = &ds->formats[i]; 2471b5d61b8Smrg break; 2481b5d61b8Smrg } 2491b5d61b8Smrg } 2501b5d61b8Smrg if (screen_format == NULL) 2511b5d61b8Smrg return BadMatch; 2521b5d61b8Smrg 2531b5d61b8Smrg if (screen_format->num_modifiers == 0) { 2541b5d61b8Smrg *num_screen_modifiers = 0; 2551b5d61b8Smrg *num_intersect_modifiers = 0; 2561b5d61b8Smrg return Success; 2571b5d61b8Smrg } 2581b5d61b8Smrg 2591b5d61b8Smrg if (!info->get_drawable_modifiers || 2601b5d61b8Smrg !info->get_drawable_modifiers(drawable, format, 2611b5d61b8Smrg &num_drawable_mods, 2621b5d61b8Smrg &drawable_mods)) { 2631b5d61b8Smrg num_drawable_mods = 0; 2641b5d61b8Smrg drawable_mods = NULL; 2651b5d61b8Smrg } 2661b5d61b8Smrg 2671b5d61b8Smrg /* We're allocating slightly more memory than necessary but it reduces 2681b5d61b8Smrg * the complexity of finding the intersection set. 2691b5d61b8Smrg */ 2701b5d61b8Smrg screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 2711b5d61b8Smrg if (!screen_mods) 2721b5d61b8Smrg return BadAlloc; 2731b5d61b8Smrg if (num_drawable_mods > 0) { 2741b5d61b8Smrg intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 2751b5d61b8Smrg if (!intersect_mods) { 2761b5d61b8Smrg free(screen_mods); 2771b5d61b8Smrg return BadAlloc; 2781b5d61b8Smrg } 2791b5d61b8Smrg } 2801b5d61b8Smrg 2811b5d61b8Smrg *num_screen_modifiers = 0; 2821b5d61b8Smrg *num_intersect_modifiers = 0; 2831b5d61b8Smrg for (i = 0; i < screen_format->num_modifiers; i++) { 2841b5d61b8Smrg CARD64 modifier = screen_format->modifiers[i]; 2851b5d61b8Smrg Bool intersect = FALSE; 2861b5d61b8Smrg 2871b5d61b8Smrg for (j = 0; j < num_drawable_mods; j++) { 2881b5d61b8Smrg if (drawable_mods[j] == modifier) { 2891b5d61b8Smrg intersect = TRUE; 2901b5d61b8Smrg break; 2911b5d61b8Smrg } 2921b5d61b8Smrg } 2931b5d61b8Smrg 2941b5d61b8Smrg if (intersect) { 2951b5d61b8Smrg intersect_mods[*num_intersect_modifiers] = modifier; 2961b5d61b8Smrg *num_intersect_modifiers += 1; 2971b5d61b8Smrg } else { 2981b5d61b8Smrg screen_mods[*num_screen_modifiers] = modifier; 2991b5d61b8Smrg *num_screen_modifiers += 1; 3001b5d61b8Smrg } 3011b5d61b8Smrg } 3021b5d61b8Smrg 3031b5d61b8Smrg assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers); 3041b5d61b8Smrg 3051b5d61b8Smrg *intersect_modifiers = intersect_mods; 3061b5d61b8Smrg *screen_modifiers = screen_mods; 3071b5d61b8Smrg free(drawable_mods); 3081b5d61b8Smrg 3091b5d61b8Smrg return Success; 3101b5d61b8Smrg} 311