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#include "dri3_priv.h" 2435c4bbdfSmrg#include <syncsdk.h> 2535c4bbdfSmrg#include <misync.h> 2635c4bbdfSmrg#include <misyncshm.h> 2735c4bbdfSmrg#include <randrstr.h> 281b5d61b8Smrg#include <drm_fourcc.h> 291b5d61b8Smrg#include <unistd.h> 3035c4bbdfSmrg 3135c4bbdfSmrgint 3235c4bbdfSmrgdri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd) 3335c4bbdfSmrg{ 3435c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 351b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 3635c4bbdfSmrg 371b5d61b8Smrg if (info == NULL) 3835c4bbdfSmrg return BadMatch; 3935c4bbdfSmrg 4035c4bbdfSmrg if (info->version >= 1 && info->open_client != NULL) 411b5d61b8Smrg return (*info->open_client) (client, screen, provider, fd); 421b5d61b8Smrg if (info->open != NULL) 431b5d61b8Smrg return (*info->open) (screen, provider, fd); 4435c4bbdfSmrg 451b5d61b8Smrg return BadMatch; 4635c4bbdfSmrg} 4735c4bbdfSmrg 4835c4bbdfSmrgint 491b5d61b8Smrgdri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, 501b5d61b8Smrg CARD8 num_fds, const int *fds, 511b5d61b8Smrg CARD16 width, CARD16 height, 521b5d61b8Smrg const CARD32 *strides, const CARD32 *offsets, 531b5d61b8Smrg CARD8 depth, CARD8 bpp, CARD64 modifier) 5435c4bbdfSmrg{ 5535c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 561b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 5735c4bbdfSmrg PixmapPtr pixmap; 5835c4bbdfSmrg 591b5d61b8Smrg if (!info) 6035c4bbdfSmrg return BadImplementation; 6135c4bbdfSmrg 621b5d61b8Smrg if (info->version >= 2 && info->pixmap_from_fds != NULL) { 631b5d61b8Smrg pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height, 641b5d61b8Smrg strides, offsets, depth, bpp, modifier); 651b5d61b8Smrg } else if (info->pixmap_from_fd != NULL && num_fds == 1) { 661b5d61b8Smrg pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height, 671b5d61b8Smrg strides[0], depth, bpp); 681b5d61b8Smrg } else { 691b5d61b8Smrg return BadImplementation; 701b5d61b8Smrg } 711b5d61b8Smrg 7235c4bbdfSmrg if (!pixmap) 7335c4bbdfSmrg return BadAlloc; 7435c4bbdfSmrg 7535c4bbdfSmrg *ppixmap = pixmap; 7635c4bbdfSmrg return Success; 7735c4bbdfSmrg} 7835c4bbdfSmrg 7935c4bbdfSmrgint 801b5d61b8Smrgdri3_fds_from_pixmap(PixmapPtr pixmap, int *fds, 811b5d61b8Smrg uint32_t *strides, uint32_t *offsets, 821b5d61b8Smrg uint64_t *modifier) 8335c4bbdfSmrg{ 8435c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 8535c4bbdfSmrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 861b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 871b5d61b8Smrg 881b5d61b8Smrg if (!info) 891b5d61b8Smrg return 0; 901b5d61b8Smrg 911b5d61b8Smrg if (info->version >= 2 && info->fds_from_pixmap != NULL) { 921b5d61b8Smrg return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets, 931b5d61b8Smrg modifier); 941b5d61b8Smrg } else if (info->fd_from_pixmap != NULL) { 951b5d61b8Smrg CARD16 stride; 961b5d61b8Smrg CARD32 size; 971b5d61b8Smrg 981b5d61b8Smrg fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size); 991b5d61b8Smrg if (fds[0] < 0) 1001b5d61b8Smrg return 0; 1011b5d61b8Smrg 1021b5d61b8Smrg strides[0] = stride; 1031b5d61b8Smrg offsets[0] = 0; 1041b5d61b8Smrg *modifier = DRM_FORMAT_MOD_INVALID; 1051b5d61b8Smrg return 1; 1061b5d61b8Smrg } else { 1071b5d61b8Smrg return 0; 1081b5d61b8Smrg } 1091b5d61b8Smrg} 1101b5d61b8Smrg 1111b5d61b8Smrgint 1121b5d61b8Smrgdri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 1131b5d61b8Smrg{ 1141b5d61b8Smrg ScreenPtr screen = pixmap->drawable.pScreen; 1151b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 1161b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 1171b5d61b8Smrg uint32_t strides[4]; 1181b5d61b8Smrg uint32_t offsets[4]; 1191b5d61b8Smrg uint64_t modifier; 1201b5d61b8Smrg int fds[4]; 1211b5d61b8Smrg int num_fds; 1221b5d61b8Smrg 1231b5d61b8Smrg if (!info) 1241b5d61b8Smrg return -1; 1251b5d61b8Smrg 1261b5d61b8Smrg /* Preferentially use the old interface, allowing the implementation to 1271b5d61b8Smrg * ensure the buffer is in a single-plane format which doesn't need 1281b5d61b8Smrg * modifiers. */ 1291b5d61b8Smrg if (info->fd_from_pixmap != NULL) 1301b5d61b8Smrg return (*info->fd_from_pixmap)(screen, pixmap, stride, size); 1311b5d61b8Smrg 1321b5d61b8Smrg if (info->version < 2 || info->fds_from_pixmap == NULL) 1331b5d61b8Smrg return -1; 1341b5d61b8Smrg 1351b5d61b8Smrg /* If using the new interface, make sure that it's a single plane starting 1361b5d61b8Smrg * at 0 within the BO. We don't check the modifier, as the client may 1371b5d61b8Smrg * have an auxiliary mechanism for determining the modifier itself. */ 1381b5d61b8Smrg num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets, 1391b5d61b8Smrg &modifier); 1401b5d61b8Smrg if (num_fds != 1 || offsets[0] != 0) { 1411b5d61b8Smrg int i; 1421b5d61b8Smrg for (i = 0; i < num_fds; i++) 1431b5d61b8Smrg close(fds[i]); 1441b5d61b8Smrg return -1; 1451b5d61b8Smrg } 1461b5d61b8Smrg 1471b5d61b8Smrg *stride = strides[0]; 1481b5d61b8Smrg *size = size[0]; 1491b5d61b8Smrg return fds[0]; 1501b5d61b8Smrg} 1511b5d61b8Smrg 1521b5d61b8Smrgstatic int 1531b5d61b8Smrgcache_formats_and_modifiers(ScreenPtr screen) 1541b5d61b8Smrg{ 1551b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 1561b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 1571b5d61b8Smrg CARD32 num_formats; 1581b5d61b8Smrg CARD32 *formats; 1591b5d61b8Smrg uint32_t num_modifiers; 1601b5d61b8Smrg uint64_t *modifiers; 1611b5d61b8Smrg int i; 1621b5d61b8Smrg 1631b5d61b8Smrg if (ds->formats_cached) 1641b5d61b8Smrg return Success; 16535c4bbdfSmrg 1661b5d61b8Smrg if (!info) 16735c4bbdfSmrg return BadImplementation; 16835c4bbdfSmrg 1691b5d61b8Smrg if (info->version < 2 || !info->get_formats || !info->get_modifiers) { 1701b5d61b8Smrg ds->formats = NULL; 1711b5d61b8Smrg ds->num_formats = 0; 1721b5d61b8Smrg ds->formats_cached = TRUE; 1731b5d61b8Smrg return Success; 1741b5d61b8Smrg } 1751b5d61b8Smrg 1761b5d61b8Smrg if (!info->get_formats(screen, &num_formats, &formats)) 1771b5d61b8Smrg return BadAlloc; 1781b5d61b8Smrg 1791b5d61b8Smrg if (!num_formats) { 1801b5d61b8Smrg ds->num_formats = 0; 1811b5d61b8Smrg ds->formats_cached = TRUE; 1821b5d61b8Smrg return Success; 1831b5d61b8Smrg } 1841b5d61b8Smrg 1851b5d61b8Smrg ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec)); 1861b5d61b8Smrg if (!ds->formats) 18735c4bbdfSmrg return BadAlloc; 1881b5d61b8Smrg 1891b5d61b8Smrg for (i = 0; i < num_formats; i++) { 1901b5d61b8Smrg dri3_dmabuf_format_ptr iter = &ds->formats[i]; 1911b5d61b8Smrg 1921b5d61b8Smrg if (!info->get_modifiers(screen, formats[i], 1931b5d61b8Smrg &num_modifiers, 1941b5d61b8Smrg &modifiers)) 1951b5d61b8Smrg continue; 1961b5d61b8Smrg 1971b5d61b8Smrg if (!num_modifiers) 1981b5d61b8Smrg continue; 1991b5d61b8Smrg 2001b5d61b8Smrg iter->format = formats[i]; 2011b5d61b8Smrg iter->num_modifiers = num_modifiers; 2021b5d61b8Smrg iter->modifiers = modifiers; 2031b5d61b8Smrg } 2041b5d61b8Smrg 2051b5d61b8Smrg ds->num_formats = i; 2061b5d61b8Smrg ds->formats_cached = TRUE; 2071b5d61b8Smrg 20835c4bbdfSmrg return Success; 20935c4bbdfSmrg} 21035c4bbdfSmrg 2111b5d61b8Smrgint 2121b5d61b8Smrgdri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, 2131b5d61b8Smrg CARD8 depth, CARD8 bpp, 2141b5d61b8Smrg CARD32 *num_intersect_modifiers, 2151b5d61b8Smrg CARD64 **intersect_modifiers, 2161b5d61b8Smrg CARD32 *num_screen_modifiers, 2171b5d61b8Smrg CARD64 **screen_modifiers) 2181b5d61b8Smrg{ 2191b5d61b8Smrg dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 2201b5d61b8Smrg const dri3_screen_info_rec *info = ds->info; 2211b5d61b8Smrg int i, j; 2221b5d61b8Smrg int ret; 2231b5d61b8Smrg uint32_t num_drawable_mods; 2241b5d61b8Smrg uint64_t *drawable_mods; 2251b5d61b8Smrg CARD64 *intersect_mods = NULL; 2261b5d61b8Smrg CARD64 *screen_mods = NULL; 2271b5d61b8Smrg CARD32 format; 2281b5d61b8Smrg dri3_dmabuf_format_ptr screen_format = NULL; 2291b5d61b8Smrg 2301b5d61b8Smrg ret = cache_formats_and_modifiers(screen); 2311b5d61b8Smrg if (ret != Success) 2321b5d61b8Smrg return ret; 2331b5d61b8Smrg 2341b5d61b8Smrg format = drm_format_for_depth(depth, bpp); 2351b5d61b8Smrg if (format == 0) 2361b5d61b8Smrg return BadValue; 2371b5d61b8Smrg 2381b5d61b8Smrg /* Find screen-global modifiers from cache 2391b5d61b8Smrg */ 2401b5d61b8Smrg for (i = 0; i < ds->num_formats; i++) { 2411b5d61b8Smrg if (ds->formats[i].format == format) { 2421b5d61b8Smrg screen_format = &ds->formats[i]; 2431b5d61b8Smrg break; 2441b5d61b8Smrg } 2451b5d61b8Smrg } 2461b5d61b8Smrg if (screen_format == NULL) 2471b5d61b8Smrg return BadMatch; 2481b5d61b8Smrg 2491b5d61b8Smrg if (screen_format->num_modifiers == 0) { 2501b5d61b8Smrg *num_screen_modifiers = 0; 2511b5d61b8Smrg *num_intersect_modifiers = 0; 2521b5d61b8Smrg return Success; 2531b5d61b8Smrg } 2541b5d61b8Smrg 2551b5d61b8Smrg if (!info->get_drawable_modifiers || 2561b5d61b8Smrg !info->get_drawable_modifiers(drawable, format, 2571b5d61b8Smrg &num_drawable_mods, 2581b5d61b8Smrg &drawable_mods)) { 2591b5d61b8Smrg num_drawable_mods = 0; 2601b5d61b8Smrg drawable_mods = NULL; 2611b5d61b8Smrg } 2621b5d61b8Smrg 2631b5d61b8Smrg /* We're allocating slightly more memory than necessary but it reduces 2641b5d61b8Smrg * the complexity of finding the intersection set. 2651b5d61b8Smrg */ 2661b5d61b8Smrg screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 2671b5d61b8Smrg if (!screen_mods) 2681b5d61b8Smrg return BadAlloc; 2691b5d61b8Smrg if (num_drawable_mods > 0) { 2701b5d61b8Smrg intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 2711b5d61b8Smrg if (!intersect_mods) { 2721b5d61b8Smrg free(screen_mods); 2731b5d61b8Smrg return BadAlloc; 2741b5d61b8Smrg } 2751b5d61b8Smrg } 2761b5d61b8Smrg 2771b5d61b8Smrg *num_screen_modifiers = 0; 2781b5d61b8Smrg *num_intersect_modifiers = 0; 2791b5d61b8Smrg for (i = 0; i < screen_format->num_modifiers; i++) { 2801b5d61b8Smrg CARD64 modifier = screen_format->modifiers[i]; 2811b5d61b8Smrg Bool intersect = FALSE; 2821b5d61b8Smrg 2831b5d61b8Smrg for (j = 0; j < num_drawable_mods; j++) { 2841b5d61b8Smrg if (drawable_mods[j] == modifier) { 2851b5d61b8Smrg intersect = TRUE; 2861b5d61b8Smrg break; 2871b5d61b8Smrg } 2881b5d61b8Smrg } 2891b5d61b8Smrg 2901b5d61b8Smrg if (intersect) { 2911b5d61b8Smrg intersect_mods[*num_intersect_modifiers] = modifier; 2921b5d61b8Smrg *num_intersect_modifiers += 1; 2931b5d61b8Smrg } else { 2941b5d61b8Smrg screen_mods[*num_screen_modifiers] = modifier; 2951b5d61b8Smrg *num_screen_modifiers += 1; 2961b5d61b8Smrg } 2971b5d61b8Smrg } 2981b5d61b8Smrg 2991b5d61b8Smrg assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers); 3001b5d61b8Smrg 3011b5d61b8Smrg *intersect_modifiers = intersect_mods; 3021b5d61b8Smrg *screen_modifiers = screen_mods; 3031b5d61b8Smrg free(drawable_mods); 3041b5d61b8Smrg 3051b5d61b8Smrg return Success; 3061b5d61b8Smrg} 307