1/* 2 * Copyright © 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "dri3_priv.h" 24#include <syncsdk.h> 25#include <misync.h> 26#include <misyncshm.h> 27#include <randrstr.h> 28#include <drm_fourcc.h> 29#include <unistd.h> 30 31int 32dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd) 33{ 34 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 35 const dri3_screen_info_rec *info = ds->info; 36 37 if (info == NULL) 38 return BadMatch; 39 40 if (info->version >= 1 && info->open_client != NULL) 41 return (*info->open_client) (client, screen, provider, fd); 42 if (info->open != NULL) 43 return (*info->open) (screen, provider, fd); 44 45 return BadMatch; 46} 47 48int 49dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, 50 CARD8 num_fds, const int *fds, 51 CARD16 width, CARD16 height, 52 const CARD32 *strides, const CARD32 *offsets, 53 CARD8 depth, CARD8 bpp, CARD64 modifier) 54{ 55 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 56 const dri3_screen_info_rec *info = ds->info; 57 PixmapPtr pixmap; 58 59 if (!info) 60 return BadImplementation; 61 62 if (info->version >= 2 && info->pixmap_from_fds != NULL) { 63 pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height, 64 strides, offsets, depth, bpp, modifier); 65 } else if (info->pixmap_from_fd != NULL && num_fds == 1) { 66 pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height, 67 strides[0], depth, bpp); 68 } else { 69 return BadImplementation; 70 } 71 72 if (!pixmap) 73 return BadAlloc; 74 75 *ppixmap = pixmap; 76 return Success; 77} 78 79int 80dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds, 81 uint32_t *strides, uint32_t *offsets, 82 uint64_t *modifier) 83{ 84 ScreenPtr screen = pixmap->drawable.pScreen; 85 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 86 const dri3_screen_info_rec *info = ds->info; 87 88 if (!info) 89 return 0; 90 91 if (info->version >= 2 && info->fds_from_pixmap != NULL) { 92 return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets, 93 modifier); 94 } else if (info->fd_from_pixmap != NULL) { 95 CARD16 stride; 96 CARD32 size; 97 98 fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size); 99 if (fds[0] < 0) 100 return 0; 101 102 strides[0] = stride; 103 offsets[0] = 0; 104 *modifier = DRM_FORMAT_MOD_INVALID; 105 return 1; 106 } else { 107 return 0; 108 } 109} 110 111int 112dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 113{ 114 ScreenPtr screen = pixmap->drawable.pScreen; 115 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 116 const dri3_screen_info_rec *info = ds->info; 117 uint32_t strides[4]; 118 uint32_t offsets[4]; 119 uint64_t modifier; 120 int fds[4]; 121 int num_fds; 122 123 if (!info) 124 return -1; 125 126 /* Preferentially use the old interface, allowing the implementation to 127 * ensure the buffer is in a single-plane format which doesn't need 128 * modifiers. */ 129 if (info->fd_from_pixmap != NULL) 130 return (*info->fd_from_pixmap)(screen, pixmap, stride, size); 131 132 if (info->version < 2 || info->fds_from_pixmap == NULL) 133 return -1; 134 135 /* If using the new interface, make sure that it's a single plane starting 136 * at 0 within the BO. We don't check the modifier, as the client may 137 * have an auxiliary mechanism for determining the modifier itself. */ 138 num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets, 139 &modifier); 140 if (num_fds != 1 || offsets[0] != 0) { 141 int i; 142 for (i = 0; i < num_fds; i++) 143 close(fds[i]); 144 return -1; 145 } 146 147 *stride = strides[0]; 148 *size = size[0]; 149 return fds[0]; 150} 151 152static int 153cache_formats_and_modifiers(ScreenPtr screen) 154{ 155 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 156 const dri3_screen_info_rec *info = ds->info; 157 CARD32 num_formats; 158 CARD32 *formats; 159 uint32_t num_modifiers; 160 uint64_t *modifiers; 161 int i; 162 163 if (ds->formats_cached) 164 return Success; 165 166 if (!info) 167 return BadImplementation; 168 169 if (info->version < 2 || !info->get_formats || !info->get_modifiers) { 170 ds->formats = NULL; 171 ds->num_formats = 0; 172 ds->formats_cached = TRUE; 173 return Success; 174 } 175 176 if (!info->get_formats(screen, &num_formats, &formats)) 177 return BadAlloc; 178 179 if (!num_formats) { 180 ds->num_formats = 0; 181 ds->formats_cached = TRUE; 182 return Success; 183 } 184 185 ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec)); 186 if (!ds->formats) 187 return BadAlloc; 188 189 for (i = 0; i < num_formats; i++) { 190 dri3_dmabuf_format_ptr iter = &ds->formats[i]; 191 192 if (!info->get_modifiers(screen, formats[i], 193 &num_modifiers, 194 &modifiers)) 195 continue; 196 197 if (!num_modifiers) 198 continue; 199 200 iter->format = formats[i]; 201 iter->num_modifiers = num_modifiers; 202 iter->modifiers = modifiers; 203 } 204 205 ds->num_formats = i; 206 ds->formats_cached = TRUE; 207 208 return Success; 209} 210 211int 212dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, 213 CARD8 depth, CARD8 bpp, 214 CARD32 *num_intersect_modifiers, 215 CARD64 **intersect_modifiers, 216 CARD32 *num_screen_modifiers, 217 CARD64 **screen_modifiers) 218{ 219 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 220 const dri3_screen_info_rec *info = ds->info; 221 int i, j; 222 int ret; 223 uint32_t num_drawable_mods; 224 uint64_t *drawable_mods; 225 CARD64 *intersect_mods = NULL; 226 CARD64 *screen_mods = NULL; 227 CARD32 format; 228 dri3_dmabuf_format_ptr screen_format = NULL; 229 230 ret = cache_formats_and_modifiers(screen); 231 if (ret != Success) 232 return ret; 233 234 format = drm_format_for_depth(depth, bpp); 235 if (format == 0) 236 return BadValue; 237 238 /* Find screen-global modifiers from cache 239 */ 240 for (i = 0; i < ds->num_formats; i++) { 241 if (ds->formats[i].format == format) { 242 screen_format = &ds->formats[i]; 243 break; 244 } 245 } 246 if (screen_format == NULL) 247 return BadMatch; 248 249 if (screen_format->num_modifiers == 0) { 250 *num_screen_modifiers = 0; 251 *num_intersect_modifiers = 0; 252 return Success; 253 } 254 255 if (!info->get_drawable_modifiers || 256 !info->get_drawable_modifiers(drawable, format, 257 &num_drawable_mods, 258 &drawable_mods)) { 259 num_drawable_mods = 0; 260 drawable_mods = NULL; 261 } 262 263 /* We're allocating slightly more memory than necessary but it reduces 264 * the complexity of finding the intersection set. 265 */ 266 screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 267 if (!screen_mods) 268 return BadAlloc; 269 if (num_drawable_mods > 0) { 270 intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 271 if (!intersect_mods) { 272 free(screen_mods); 273 return BadAlloc; 274 } 275 } 276 277 *num_screen_modifiers = 0; 278 *num_intersect_modifiers = 0; 279 for (i = 0; i < screen_format->num_modifiers; i++) { 280 CARD64 modifier = screen_format->modifiers[i]; 281 Bool intersect = FALSE; 282 283 for (j = 0; j < num_drawable_mods; j++) { 284 if (drawable_mods[j] == modifier) { 285 intersect = TRUE; 286 break; 287 } 288 } 289 290 if (intersect) { 291 intersect_mods[*num_intersect_modifiers] = modifier; 292 *num_intersect_modifiers += 1; 293 } else { 294 screen_mods[*num_screen_modifiers] = modifier; 295 *num_screen_modifiers += 1; 296 } 297 } 298 299 assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers); 300 301 *intersect_modifiers = intersect_mods; 302 *screen_modifiers = screen_mods; 303 free(drawable_mods); 304 305 return Success; 306} 307