307 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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 <syncsdk.h>
 | |
| #include <misync.h>
 | |
| #include <misyncshm.h>
 | |
| #include <randrstr.h>
 | |
| #include <drm_fourcc.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| 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)
 | |
|         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;
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
 | |
|                              CARD8 depth, CARD8 bpp,
 | |
|                              CARD32 *num_intersect_modifiers,
 | |
|                              CARD64 **intersect_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, j;
 | |
|     int                         ret;
 | |
|     uint32_t                    num_drawable_mods;
 | |
|     uint64_t                   *drawable_mods;
 | |
|     CARD64                     *intersect_mods = NULL;
 | |
|     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_intersect_modifiers = 0;
 | |
|         return Success;
 | |
|     }
 | |
| 
 | |
|     if (!info->get_drawable_modifiers ||
 | |
|         !info->get_drawable_modifiers(drawable, format,
 | |
|                                       &num_drawable_mods,
 | |
|                                       &drawable_mods)) {
 | |
|         num_drawable_mods = 0;
 | |
|         drawable_mods = NULL;
 | |
|     }
 | |
| 
 | |
|     /* We're allocating slightly more memory than necessary but it reduces
 | |
|      * the complexity of finding the intersection set.
 | |
|      */
 | |
|     screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
 | |
|     if (!screen_mods)
 | |
|         return BadAlloc;
 | |
|     if (num_drawable_mods > 0) {
 | |
|         intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
 | |
|         if (!intersect_mods) {
 | |
|             free(screen_mods);
 | |
|             return BadAlloc;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     *num_screen_modifiers = 0;
 | |
|     *num_intersect_modifiers = 0;
 | |
|     for (i = 0; i < screen_format->num_modifiers; i++) {
 | |
|         CARD64 modifier = screen_format->modifiers[i];
 | |
|         Bool intersect = FALSE;
 | |
| 
 | |
|         for (j = 0; j < num_drawable_mods; j++) {
 | |
|             if (drawable_mods[j] == modifier) {
 | |
|                 intersect = TRUE;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (intersect) {
 | |
|             intersect_mods[*num_intersect_modifiers] = modifier;
 | |
|             *num_intersect_modifiers += 1;
 | |
|         } else {
 | |
|             screen_mods[*num_screen_modifiers] = modifier;
 | |
|             *num_screen_modifiers += 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
 | |
| 
 | |
|     *intersect_modifiers = intersect_mods;
 | |
|     *screen_modifiers = screen_mods;
 | |
|     free(drawable_mods);
 | |
| 
 | |
|     return Success;
 | |
| }
 |