sna_dri3.c revision 42542f5f
1/* 2 * Copyright (c) 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include <sys/types.h> 30#include <fcntl.h> 31#include <unistd.h> 32#include <errno.h> 33#include <xf86drm.h> 34 35#include "sna.h" 36 37#include <xf86.h> 38#include <dri3.h> 39#include <misyncshm.h> 40#include <misyncstr.h> 41 42static DevPrivateKeyRec sna_sync_fence_private_key; 43struct sna_sync_fence { 44 SyncFenceSetTriggeredFunc set_triggered; 45}; 46 47static inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence) 48{ 49 return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key); 50} 51 52static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv) 53{ 54 struct kgem_bo *bo = NULL; 55 56 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 57 assert(priv); 58 59 if (priv->pinned & PIN_DRI3) { 60 assert(priv->gpu_bo); 61 assert(priv->pinned & PIN_DRI3); 62 DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle)); 63 if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) { 64 sna_damage_all(&priv->gpu_damage, priv->pixmap); 65 bo = priv->gpu_bo; 66 } 67 } else { 68 assert(priv->cpu_bo); 69 assert(IS_STATIC_PTR(priv->ptr)); 70 DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle)); 71 if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 72 bo = priv->cpu_bo; 73 } 74 75 if (bo != NULL) { 76 kgem_bo_submit(&sna->kgem, bo); 77 kgem_bo_unclean(&sna->kgem, bo); 78 } 79} 80 81static void 82sna_sync_fence_set_triggered(SyncFence *fence) 83{ 84 struct sna *sna = to_sna_from_screen(fence->pScreen); 85 struct sna_sync_fence *sna_fence = sna_sync_fence(fence); 86 DrawablePtr draw = NULL; 87 88 DBG(("%s()\n", __FUNCTION__)); 89 90#if 0 91 draw = miSyncShmFenceGetDrawable(fence); 92#endif 93 if (draw) { 94 DBG(("%s: associated pixmap=%ld\n", __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber)); 95 sna_sync_flush(sna, sna_pixmap(get_drawable_pixmap(draw))); 96 } else { /* SyncFence are currently per-screen, sigh */ 97 struct sna_pixmap *priv; 98 99 DBG(("%s: flushing all DRI3 pixmaps\n", __FUNCTION__)); 100 list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) 101 sna_sync_flush(sna, priv); 102 103 sna_accel_flush(sna); 104 } 105 106 DBG(("%s: complete, chaining up\n", __FUNCTION__)); 107 fence->funcs.SetTriggered = sna_fence->set_triggered; 108 sna_fence->set_triggered(fence); 109 sna_fence->set_triggered = fence->funcs.SetTriggered; 110 fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 111} 112 113static void 114sna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered) 115{ 116 struct sna *sna = to_sna_from_screen(screen); 117 SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen); 118 119 DBG(("%s()\n", __FUNCTION__)); 120 121 funcs->CreateFence = sna->dri3.create_fence; 122 sna->dri3.create_fence(screen, fence, initially_triggered); 123 sna->dri3.create_fence = funcs->CreateFence; 124 funcs->CreateFence = sna_sync_create_fence; 125 126 sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered; 127 fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 128} 129 130static bool 131sna_sync_open(struct sna *sna, ScreenPtr screen) 132{ 133 SyncScreenFuncsPtr funcs; 134 135 DBG(("%s()\n", __FUNCTION__)); 136 137 if (!miSyncShmScreenInit(screen)) 138 return false; 139 140 if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) { 141 if (!dixRegisterPrivateKey(&sna_sync_fence_private_key, 142 PRIVATE_SYNC_FENCE, 143 sizeof(struct sna_sync_fence))) 144 return false; 145 } 146 147 funcs = miSyncGetScreenFuncs(screen); 148 sna->dri3.create_fence = funcs->CreateFence; 149 funcs->CreateFence = sna_sync_create_fence; 150 151 return true; 152} 153 154static int sna_dri3_open_device(ScreenPtr screen, 155 RRProviderPtr provider, 156 int *out) 157{ 158 int fd; 159 160 DBG(("%s()\n", __FUNCTION__)); 161 fd = intel_get_client_fd(xf86ScreenToScrn(screen)); 162 if (fd < 0) 163 return -fd; 164 165 *out = fd; 166 return Success; 167} 168 169static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen, 170 int fd, 171 CARD16 width, 172 CARD16 height, 173 CARD16 stride, 174 CARD8 depth, 175 CARD8 bpp) 176{ 177 struct sna *sna = to_sna_from_screen(screen); 178 PixmapPtr pixmap; 179 struct sna_pixmap *priv; 180 struct kgem_bo *bo; 181 182 DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n", 183 __FUNCTION__, fd, width, height, stride, depth, bpp)); 184 if (width > INT16_MAX || height > INT16_MAX) 185 return NULL; 186 187 if ((uint32_t)width * bpp > (uint32_t)stride * 8) 188 return NULL; 189 190 if (depth < 8) 191 return NULL; 192 193 switch (bpp) { 194 case 8: 195 case 16: 196 case 32: 197 break; 198 default: 199 return NULL; 200 } 201 202 bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height); 203 if (bo == NULL) 204 return NULL; 205 206 /* Check for a duplicate */ 207 list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) { 208 int other_stride = 0; 209 if (bo->snoop) { 210 assert(priv->cpu_bo); 211 assert(IS_STATIC_PTR(priv->ptr)); 212 if (bo->handle == priv->cpu_bo->handle) 213 other_stride = priv->cpu_bo->pitch; 214 } else { 215 assert(priv->gpu_bo); 216 assert(priv->pinned & PIN_DRI3); 217 if (bo->handle == priv->gpu_bo->handle) 218 other_stride = priv->gpu_bo->pitch; 219 } 220 if (other_stride) { 221 pixmap = priv->pixmap; 222 DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 223 bo->handle = 0; /* fudge to prevent gem_close */ 224 kgem_bo_destroy(&sna->kgem, bo); 225 if (width != pixmap->drawable.width || 226 height != pixmap->drawable.height || 227 depth != pixmap->drawable.depth || 228 bpp != pixmap->drawable.bitsPerPixel || 229 stride != other_stride) { 230 DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__, 231 pixmap->drawable.width, 232 pixmap->drawable.height, 233 pixmap->drawable.depth, 234 pixmap->drawable.bitsPerPixel, 235 other_stride)); 236 return NULL; 237 } 238 sna_sync_flush(sna, priv); 239 pixmap->refcnt++; 240 return pixmap; 241 } 242 } 243 244 if (!kgem_check_surface_size(&sna->kgem, 245 width, height, bpp, 246 bo->tiling, stride, kgem_bo_size(bo))) { 247 DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n", 248 __FUNCTION__, stride, kgem_bo_size(bo), width, height)); 249 goto free_bo; 250 } 251 252 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 253 if (pixmap == NullPixmap) 254 goto free_bo; 255 256 if (!screen->ModifyPixmapHeader(pixmap, width, height, 257 depth, bpp, stride, NULL)) 258 goto free_pixmap; 259 260 priv = sna_pixmap_attach_to_bo(pixmap, bo); 261 if (priv == NULL) 262 goto free_pixmap; 263 264 bo->pitch = stride; 265 priv->stride = stride; 266 267 if (bo->snoop) { 268 assert(priv->cpu_bo == bo); 269 pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 270 if (pixmap->devPrivate.ptr == NULL) 271 goto free_pixmap; 272 273 pixmap->devKind = stride; 274 priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 275 } else { 276 assert(priv->gpu_bo == bo); 277 priv->pinned |= PIN_DRI3; 278 } 279 list_add(&priv->cow_list, &sna->dri3.pixmaps); 280 281 return pixmap; 282 283free_pixmap: 284 screen->DestroyPixmap(pixmap); 285free_bo: 286 kgem_bo_destroy(&sna->kgem, bo); 287 return NULL; 288} 289 290static int sna_dri3_fd_from_pixmap(ScreenPtr screen, 291 PixmapPtr pixmap, 292 CARD16 *stride, 293 CARD32 *size) 294{ 295 struct sna *sna = to_sna_from_screen(screen); 296 struct sna_pixmap *priv; 297 struct kgem_bo *bo = NULL; 298 int fd; 299 300 DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__, 301 pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 302 if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) { 303 DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__)); 304 return -1; 305 } 306 307 priv = sna_pixmap(pixmap); 308 if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { 309 if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 310 bo = priv->cpu_bo; 311 } else { 312 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI); 313 if (priv != NULL) { 314 sna_damage_all(&priv->gpu_damage, pixmap); 315 bo = priv->gpu_bo; 316 } 317 } 318 if (bo == NULL) { 319 DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__)); 320 return -1; 321 } 322 assert(priv != NULL); 323 324 if (bo->pitch > UINT16_MAX) { 325 DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n", 326 __FUNCTION__, bo->pitch)); 327 return -1; 328 } 329 330 fd = kgem_bo_export_to_prime(&sna->kgem, bo); 331 if (fd == -1) { 332 DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle)); 333 return -1; 334 } 335 336 if (bo == priv->gpu_bo) 337 priv->pinned |= PIN_DRI3; 338 list_move(&priv->cow_list, &sna->dri3.pixmaps); 339 340 *stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch; 341 *size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo); 342 DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n", 343 __FUNCTION__, 344 (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber, 345 (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle, 346 *stride, *size)); 347 return fd; 348} 349 350static dri3_screen_info_rec sna_dri3_info = { 351 .version = DRI3_SCREEN_INFO_VERSION, 352 353 .open = sna_dri3_open_device, 354 .pixmap_from_fd = sna_dri3_pixmap_from_fd, 355 .fd_from_pixmap = sna_dri3_fd_from_pixmap, 356}; 357 358bool sna_dri3_open(struct sna *sna, ScreenPtr screen) 359{ 360 DBG(("%s()\n", __FUNCTION__)); 361 362 if (!sna_sync_open(sna, screen)) 363 return false; 364 365 list_init(&sna->dri3.pixmaps); 366 return dri3_screen_init(screen, &sna_dri3_info); 367} 368 369void sna_dri3_close(struct sna *sna, ScreenPtr screen) 370{ 371 SyncScreenFuncsPtr funcs; 372 373 DBG(("%s()\n", __FUNCTION__)); 374 375 funcs = miSyncGetScreenFuncs(screen); 376 if (funcs) 377 funcs->CreateFence = sna->dri3.create_fence; 378} 379