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