dri3_screen.c revision 1b5d61b8
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#ifdef HAVE_XORG_CONFIG_H 24#include <xorg-config.h> 25#endif 26 27#include "dri3_priv.h" 28#include <syncsdk.h> 29#include <misync.h> 30#include <misyncshm.h> 31#include <randrstr.h> 32#include <drm_fourcc.h> 33#include <unistd.h> 34 35int 36dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd) 37{ 38 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 39 const dri3_screen_info_rec *info = ds->info; 40 41 if (info == NULL) 42 return BadMatch; 43 44 if (info->version >= 1 && info->open_client != NULL) 45 return (*info->open_client) (client, screen, provider, fd); 46 if (info->open != NULL) 47 return (*info->open) (screen, provider, fd); 48 49 return BadMatch; 50} 51 52int 53dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, 54 CARD8 num_fds, const int *fds, 55 CARD16 width, CARD16 height, 56 const CARD32 *strides, const CARD32 *offsets, 57 CARD8 depth, CARD8 bpp, CARD64 modifier) 58{ 59 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 60 const dri3_screen_info_rec *info = ds->info; 61 PixmapPtr pixmap; 62 63 if (!info) 64 return BadImplementation; 65 66 if (info->version >= 2 && info->pixmap_from_fds != NULL) { 67 pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height, 68 strides, offsets, depth, bpp, modifier); 69 } else if (info->pixmap_from_fd != NULL && num_fds == 1) { 70 pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height, 71 strides[0], depth, bpp); 72 } else { 73 return BadImplementation; 74 } 75 76 if (!pixmap) 77 return BadAlloc; 78 79 *ppixmap = pixmap; 80 return Success; 81} 82 83int 84dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds, 85 uint32_t *strides, uint32_t *offsets, 86 uint64_t *modifier) 87{ 88 ScreenPtr screen = pixmap->drawable.pScreen; 89 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 90 const dri3_screen_info_rec *info = ds->info; 91 92 if (!info) 93 return 0; 94 95 if (info->version >= 2 && info->fds_from_pixmap != NULL) { 96 return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets, 97 modifier); 98 } else if (info->fd_from_pixmap != NULL) { 99 CARD16 stride; 100 CARD32 size; 101 102 fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size); 103 if (fds[0] < 0) 104 return 0; 105 106 strides[0] = stride; 107 offsets[0] = 0; 108 *modifier = DRM_FORMAT_MOD_INVALID; 109 return 1; 110 } else { 111 return 0; 112 } 113} 114 115int 116dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 117{ 118 ScreenPtr screen = pixmap->drawable.pScreen; 119 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 120 const dri3_screen_info_rec *info = ds->info; 121 uint32_t strides[4]; 122 uint32_t offsets[4]; 123 uint64_t modifier; 124 int fds[4]; 125 int num_fds; 126 127 if (!info) 128 return -1; 129 130 /* Preferentially use the old interface, allowing the implementation to 131 * ensure the buffer is in a single-plane format which doesn't need 132 * modifiers. */ 133 if (info->fd_from_pixmap != NULL) 134 return (*info->fd_from_pixmap)(screen, pixmap, stride, size); 135 136 if (info->version < 2 || info->fds_from_pixmap == NULL) 137 return -1; 138 139 /* If using the new interface, make sure that it's a single plane starting 140 * at 0 within the BO. We don't check the modifier, as the client may 141 * have an auxiliary mechanism for determining the modifier itself. */ 142 num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets, 143 &modifier); 144 if (num_fds != 1 || offsets[0] != 0) { 145 int i; 146 for (i = 0; i < num_fds; i++) 147 close(fds[i]); 148 return -1; 149 } 150 151 *stride = strides[0]; 152 *size = size[0]; 153 return fds[0]; 154} 155 156static int 157cache_formats_and_modifiers(ScreenPtr screen) 158{ 159 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 160 const dri3_screen_info_rec *info = ds->info; 161 CARD32 num_formats; 162 CARD32 *formats; 163 uint32_t num_modifiers; 164 uint64_t *modifiers; 165 int i; 166 167 if (ds->formats_cached) 168 return Success; 169 170 if (!info) 171 return BadImplementation; 172 173 if (info->version < 2 || !info->get_formats || !info->get_modifiers) { 174 ds->formats = NULL; 175 ds->num_formats = 0; 176 ds->formats_cached = TRUE; 177 return Success; 178 } 179 180 if (!info->get_formats(screen, &num_formats, &formats)) 181 return BadAlloc; 182 183 if (!num_formats) { 184 ds->num_formats = 0; 185 ds->formats_cached = TRUE; 186 return Success; 187 } 188 189 ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec)); 190 if (!ds->formats) 191 return BadAlloc; 192 193 for (i = 0; i < num_formats; i++) { 194 dri3_dmabuf_format_ptr iter = &ds->formats[i]; 195 196 if (!info->get_modifiers(screen, formats[i], 197 &num_modifiers, 198 &modifiers)) 199 continue; 200 201 if (!num_modifiers) 202 continue; 203 204 iter->format = formats[i]; 205 iter->num_modifiers = num_modifiers; 206 iter->modifiers = modifiers; 207 } 208 209 ds->num_formats = i; 210 ds->formats_cached = TRUE; 211 212 return Success; 213} 214 215int 216dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, 217 CARD8 depth, CARD8 bpp, 218 CARD32 *num_intersect_modifiers, 219 CARD64 **intersect_modifiers, 220 CARD32 *num_screen_modifiers, 221 CARD64 **screen_modifiers) 222{ 223 dri3_screen_priv_ptr ds = dri3_screen_priv(screen); 224 const dri3_screen_info_rec *info = ds->info; 225 int i, j; 226 int ret; 227 uint32_t num_drawable_mods; 228 uint64_t *drawable_mods; 229 CARD64 *intersect_mods = NULL; 230 CARD64 *screen_mods = NULL; 231 CARD32 format; 232 dri3_dmabuf_format_ptr screen_format = NULL; 233 234 ret = cache_formats_and_modifiers(screen); 235 if (ret != Success) 236 return ret; 237 238 format = drm_format_for_depth(depth, bpp); 239 if (format == 0) 240 return BadValue; 241 242 /* Find screen-global modifiers from cache 243 */ 244 for (i = 0; i < ds->num_formats; i++) { 245 if (ds->formats[i].format == format) { 246 screen_format = &ds->formats[i]; 247 break; 248 } 249 } 250 if (screen_format == NULL) 251 return BadMatch; 252 253 if (screen_format->num_modifiers == 0) { 254 *num_screen_modifiers = 0; 255 *num_intersect_modifiers = 0; 256 return Success; 257 } 258 259 if (!info->get_drawable_modifiers || 260 !info->get_drawable_modifiers(drawable, format, 261 &num_drawable_mods, 262 &drawable_mods)) { 263 num_drawable_mods = 0; 264 drawable_mods = NULL; 265 } 266 267 /* We're allocating slightly more memory than necessary but it reduces 268 * the complexity of finding the intersection set. 269 */ 270 screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 271 if (!screen_mods) 272 return BadAlloc; 273 if (num_drawable_mods > 0) { 274 intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64)); 275 if (!intersect_mods) { 276 free(screen_mods); 277 return BadAlloc; 278 } 279 } 280 281 *num_screen_modifiers = 0; 282 *num_intersect_modifiers = 0; 283 for (i = 0; i < screen_format->num_modifiers; i++) { 284 CARD64 modifier = screen_format->modifiers[i]; 285 Bool intersect = FALSE; 286 287 for (j = 0; j < num_drawable_mods; j++) { 288 if (drawable_mods[j] == modifier) { 289 intersect = TRUE; 290 break; 291 } 292 } 293 294 if (intersect) { 295 intersect_mods[*num_intersect_modifiers] = modifier; 296 *num_intersect_modifiers += 1; 297 } else { 298 screen_mods[*num_screen_modifiers] = modifier; 299 *num_screen_modifiers += 1; 300 } 301 } 302 303 assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers); 304 305 *intersect_modifiers = intersect_mods; 306 *screen_modifiers = screen_mods; 307 free(drawable_mods); 308 309 return Success; 310} 311