1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright (c) 2014 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg */ 24428d7b3dSmrg 25428d7b3dSmrg#ifdef HAVE_CONFIG_H 26428d7b3dSmrg#include "config.h" 27428d7b3dSmrg#endif 28428d7b3dSmrg 29428d7b3dSmrg#include <sys/types.h> 30428d7b3dSmrg#include <fcntl.h> 31428d7b3dSmrg#include <unistd.h> 32428d7b3dSmrg#include <errno.h> 33428d7b3dSmrg#include <xf86drm.h> 34428d7b3dSmrg 35428d7b3dSmrg#include "sna.h" 36428d7b3dSmrg 37428d7b3dSmrg#include <xf86.h> 38428d7b3dSmrg#include <dri3.h> 39428d7b3dSmrg#include <misyncshm.h> 40428d7b3dSmrg#include <misyncstr.h> 41428d7b3dSmrg 42428d7b3dSmrgstatic DevPrivateKeyRec sna_sync_fence_private_key; 43428d7b3dSmrgstruct sna_sync_fence { 44428d7b3dSmrg SyncFenceSetTriggeredFunc set_triggered; 45428d7b3dSmrg}; 46428d7b3dSmrg 47428d7b3dSmrgstatic inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence) 48428d7b3dSmrg{ 49428d7b3dSmrg return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key); 50428d7b3dSmrg} 51428d7b3dSmrg 52428d7b3dSmrgstatic inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, struct kgem_bo *bo) 53428d7b3dSmrg{ 54428d7b3dSmrg bo->flush = true; 55428d7b3dSmrg if (bo->exec) 56428d7b3dSmrg sna->kgem.flush = 1; 57428d7b3dSmrg if (bo == priv->gpu_bo) 58428d7b3dSmrg priv->flush |= 3; 59428d7b3dSmrg else 60428d7b3dSmrg priv->shm = true; 61428d7b3dSmrg 62428d7b3dSmrg sna_accel_watch_flush(sna, 1); 63428d7b3dSmrg} 64428d7b3dSmrg 65428d7b3dSmrgstatic void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv) 66428d7b3dSmrg{ 67428d7b3dSmrg struct kgem_bo *bo = NULL; 68428d7b3dSmrg 69428d7b3dSmrg DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 70428d7b3dSmrg assert(priv); 71428d7b3dSmrg 72428d7b3dSmrg if (priv->pinned & PIN_DRI3) { 73428d7b3dSmrg assert(priv->gpu_bo); 74428d7b3dSmrg assert(priv->pinned & PIN_DRI3); 75428d7b3dSmrg DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle)); 76428d7b3dSmrg if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) { 77428d7b3dSmrg sna_damage_all(&priv->gpu_damage, priv->pixmap); 78428d7b3dSmrg bo = priv->gpu_bo; 79428d7b3dSmrg } 80428d7b3dSmrg } else { 81428d7b3dSmrg assert(priv->cpu_bo); 82428d7b3dSmrg assert(IS_STATIC_PTR(priv->ptr)); 83428d7b3dSmrg DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle)); 84428d7b3dSmrg if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 85428d7b3dSmrg bo = priv->cpu_bo; 86428d7b3dSmrg } 87428d7b3dSmrg 88428d7b3dSmrg if (bo != NULL) { 89428d7b3dSmrg kgem_bo_submit(&sna->kgem, bo); 90428d7b3dSmrg kgem_bo_unclean(&sna->kgem, bo); 91428d7b3dSmrg } 92428d7b3dSmrg} 93428d7b3dSmrg 94428d7b3dSmrgstatic void 95428d7b3dSmrgsna_sync_fence_set_triggered(SyncFence *fence) 96428d7b3dSmrg{ 97428d7b3dSmrg struct sna *sna = to_sna_from_screen(fence->pScreen); 98428d7b3dSmrg struct sna_sync_fence *sna_fence = sna_sync_fence(fence); 99428d7b3dSmrg 100428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 101428d7b3dSmrg sna_accel_flush(sna); 102428d7b3dSmrg 103428d7b3dSmrg fence->funcs.SetTriggered = sna_fence->set_triggered; 104428d7b3dSmrg sna_fence->set_triggered(fence); 105428d7b3dSmrg sna_fence->set_triggered = fence->funcs.SetTriggered; 106428d7b3dSmrg fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 107428d7b3dSmrg} 108428d7b3dSmrg 109428d7b3dSmrgstatic void 110428d7b3dSmrgsna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered) 111428d7b3dSmrg{ 112428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 113428d7b3dSmrg SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen); 114428d7b3dSmrg 115428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 116428d7b3dSmrg 117428d7b3dSmrg funcs->CreateFence = sna->dri3.create_fence; 118428d7b3dSmrg sna->dri3.create_fence(screen, fence, initially_triggered); 119428d7b3dSmrg sna->dri3.create_fence = funcs->CreateFence; 120428d7b3dSmrg funcs->CreateFence = sna_sync_create_fence; 121428d7b3dSmrg 122428d7b3dSmrg sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered; 123428d7b3dSmrg fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 124428d7b3dSmrg} 125428d7b3dSmrg 126428d7b3dSmrgstatic bool 127428d7b3dSmrgsna_sync_open(struct sna *sna, ScreenPtr screen) 128428d7b3dSmrg{ 129428d7b3dSmrg SyncScreenFuncsPtr funcs; 130428d7b3dSmrg 131428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 132428d7b3dSmrg 133428d7b3dSmrg if (!miSyncShmScreenInit(screen)) 134428d7b3dSmrg return false; 135428d7b3dSmrg 136428d7b3dSmrg if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) { 137428d7b3dSmrg if (!dixRegisterPrivateKey(&sna_sync_fence_private_key, 138428d7b3dSmrg PRIVATE_SYNC_FENCE, 139428d7b3dSmrg sizeof(struct sna_sync_fence))) 140428d7b3dSmrg return false; 141428d7b3dSmrg } 142428d7b3dSmrg 143428d7b3dSmrg funcs = miSyncGetScreenFuncs(screen); 144428d7b3dSmrg sna->dri3.create_fence = funcs->CreateFence; 145428d7b3dSmrg funcs->CreateFence = sna_sync_create_fence; 146428d7b3dSmrg 147428d7b3dSmrg return true; 148428d7b3dSmrg} 149428d7b3dSmrg 150428d7b3dSmrgstatic int sna_dri3_open_device(ScreenPtr screen, 151428d7b3dSmrg RRProviderPtr provider, 152428d7b3dSmrg int *out) 153428d7b3dSmrg{ 154428d7b3dSmrg int fd; 155428d7b3dSmrg 156428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 157428d7b3dSmrg fd = intel_get_client_fd(to_sna_from_screen(screen)->dev); 158428d7b3dSmrg if (fd < 0) 159428d7b3dSmrg return -fd; 160428d7b3dSmrg 161428d7b3dSmrg *out = fd; 162428d7b3dSmrg return Success; 163428d7b3dSmrg} 164428d7b3dSmrg 165428d7b3dSmrgstatic PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen, 166428d7b3dSmrg int fd, 167428d7b3dSmrg CARD16 width, 168428d7b3dSmrg CARD16 height, 169428d7b3dSmrg CARD16 stride, 170428d7b3dSmrg CARD8 depth, 171428d7b3dSmrg CARD8 bpp) 172428d7b3dSmrg{ 173428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 174428d7b3dSmrg PixmapPtr pixmap; 175428d7b3dSmrg struct sna_pixmap *priv; 176428d7b3dSmrg struct kgem_bo *bo; 177428d7b3dSmrg 178428d7b3dSmrg DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n", 179428d7b3dSmrg __FUNCTION__, fd, width, height, stride, depth, bpp)); 180428d7b3dSmrg if (width > INT16_MAX || height > INT16_MAX) 181428d7b3dSmrg return NULL; 182428d7b3dSmrg 183428d7b3dSmrg if ((uint32_t)width * bpp > (uint32_t)stride * 8) 184428d7b3dSmrg return NULL; 185428d7b3dSmrg 186428d7b3dSmrg if (depth < 8) 187428d7b3dSmrg return NULL; 188428d7b3dSmrg 189428d7b3dSmrg switch (bpp) { 190428d7b3dSmrg case 8: 191428d7b3dSmrg case 16: 192428d7b3dSmrg case 32: 193428d7b3dSmrg break; 194428d7b3dSmrg default: 195428d7b3dSmrg return NULL; 196428d7b3dSmrg } 197428d7b3dSmrg 198428d7b3dSmrg bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height); 199428d7b3dSmrg if (bo == NULL) 200428d7b3dSmrg return NULL; 201428d7b3dSmrg 202428d7b3dSmrg /* Check for a duplicate */ 203428d7b3dSmrg list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) { 204428d7b3dSmrg int other_stride = 0; 205428d7b3dSmrg if (bo->snoop) { 206428d7b3dSmrg assert(priv->cpu_bo); 207428d7b3dSmrg assert(IS_STATIC_PTR(priv->ptr)); 208428d7b3dSmrg if (bo->handle == priv->cpu_bo->handle) 209428d7b3dSmrg other_stride = priv->cpu_bo->pitch; 210428d7b3dSmrg } else { 211428d7b3dSmrg assert(priv->gpu_bo); 212428d7b3dSmrg assert(priv->pinned & PIN_DRI3); 213428d7b3dSmrg if (bo->handle == priv->gpu_bo->handle) 214428d7b3dSmrg other_stride = priv->gpu_bo->pitch; 215428d7b3dSmrg } 216428d7b3dSmrg if (other_stride) { 217428d7b3dSmrg pixmap = priv->pixmap; 218428d7b3dSmrg DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 219428d7b3dSmrg bo->handle = 0; /* fudge to prevent gem_close */ 220428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 221428d7b3dSmrg if (width != pixmap->drawable.width || 222428d7b3dSmrg height != pixmap->drawable.height || 223428d7b3dSmrg depth != pixmap->drawable.depth || 224428d7b3dSmrg bpp != pixmap->drawable.bitsPerPixel || 225428d7b3dSmrg stride != other_stride) { 226428d7b3dSmrg DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__, 227428d7b3dSmrg pixmap->drawable.width, 228428d7b3dSmrg pixmap->drawable.height, 229428d7b3dSmrg pixmap->drawable.depth, 230428d7b3dSmrg pixmap->drawable.bitsPerPixel, 231428d7b3dSmrg other_stride)); 232428d7b3dSmrg return NULL; 233428d7b3dSmrg } 234428d7b3dSmrg sna_sync_flush(sna, priv); 235428d7b3dSmrg pixmap->refcnt++; 236428d7b3dSmrg return pixmap; 237428d7b3dSmrg } 238428d7b3dSmrg } 239428d7b3dSmrg 240428d7b3dSmrg if (!kgem_check_surface_size(&sna->kgem, 241428d7b3dSmrg width, height, bpp, 242428d7b3dSmrg bo->tiling, stride, kgem_bo_size(bo))) { 243428d7b3dSmrg DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n", 244428d7b3dSmrg __FUNCTION__, stride, kgem_bo_size(bo), width, height)); 245428d7b3dSmrg goto free_bo; 246428d7b3dSmrg } 247428d7b3dSmrg 248428d7b3dSmrg pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 249428d7b3dSmrg if (pixmap == NullPixmap) 250428d7b3dSmrg goto free_bo; 251428d7b3dSmrg 252428d7b3dSmrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 253428d7b3dSmrg depth, bpp, stride, NULL)) 254428d7b3dSmrg goto free_pixmap; 255428d7b3dSmrg 256428d7b3dSmrg priv = sna_pixmap_attach_to_bo(pixmap, bo); 257428d7b3dSmrg if (priv == NULL) 258428d7b3dSmrg goto free_pixmap; 259428d7b3dSmrg 260428d7b3dSmrg bo->pitch = stride; 261428d7b3dSmrg priv->stride = stride; 262428d7b3dSmrg 263428d7b3dSmrg if (bo->snoop) { 264428d7b3dSmrg assert(priv->cpu_bo == bo); 265428d7b3dSmrg pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 266428d7b3dSmrg if (pixmap->devPrivate.ptr == NULL) 267428d7b3dSmrg goto free_pixmap; 268428d7b3dSmrg 269428d7b3dSmrg pixmap->devKind = stride; 270428d7b3dSmrg priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 271428d7b3dSmrg } else { 272428d7b3dSmrg assert(priv->gpu_bo == bo); 273428d7b3dSmrg priv->pinned |= PIN_DRI3; 274428d7b3dSmrg } 275428d7b3dSmrg list_add(&priv->cow_list, &sna->dri3.pixmaps); 276428d7b3dSmrg 277428d7b3dSmrg mark_dri3_pixmap(sna, priv, bo); 278428d7b3dSmrg 279428d7b3dSmrg return pixmap; 280428d7b3dSmrg 281428d7b3dSmrgfree_pixmap: 282428d7b3dSmrg screen->DestroyPixmap(pixmap); 283428d7b3dSmrgfree_bo: 284428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 285428d7b3dSmrg return NULL; 286428d7b3dSmrg} 287428d7b3dSmrg 288428d7b3dSmrgstatic int sna_dri3_fd_from_pixmap(ScreenPtr screen, 289428d7b3dSmrg PixmapPtr pixmap, 290428d7b3dSmrg CARD16 *stride, 291428d7b3dSmrg CARD32 *size) 292428d7b3dSmrg{ 293428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 294428d7b3dSmrg struct sna_pixmap *priv; 295428d7b3dSmrg struct kgem_bo *bo = NULL; 296428d7b3dSmrg int fd; 297428d7b3dSmrg 298428d7b3dSmrg DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__, 299428d7b3dSmrg pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 300428d7b3dSmrg if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) { 301428d7b3dSmrg DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__)); 302428d7b3dSmrg return -1; 303428d7b3dSmrg } 304428d7b3dSmrg 305428d7b3dSmrg priv = sna_pixmap(pixmap); 306428d7b3dSmrg if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { 307428d7b3dSmrg if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 308428d7b3dSmrg bo = priv->cpu_bo; 309428d7b3dSmrg } else { 310428d7b3dSmrg priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI); 311428d7b3dSmrg if (priv != NULL) { 312428d7b3dSmrg sna_damage_all(&priv->gpu_damage, pixmap); 313428d7b3dSmrg bo = priv->gpu_bo; 314428d7b3dSmrg } 315428d7b3dSmrg } 316428d7b3dSmrg if (bo == NULL) { 317428d7b3dSmrg DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__)); 318428d7b3dSmrg return -1; 319428d7b3dSmrg } 320428d7b3dSmrg assert(priv != NULL); 321428d7b3dSmrg 322428d7b3dSmrg if (bo->pitch > UINT16_MAX) { 323428d7b3dSmrg DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n", 324428d7b3dSmrg __FUNCTION__, bo->pitch)); 325428d7b3dSmrg return -1; 326428d7b3dSmrg } 327428d7b3dSmrg 328428d7b3dSmrg fd = kgem_bo_export_to_prime(&sna->kgem, bo); 329428d7b3dSmrg if (fd == -1) { 330428d7b3dSmrg DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle)); 331428d7b3dSmrg return -1; 332428d7b3dSmrg } 333428d7b3dSmrg 334428d7b3dSmrg if (bo == priv->gpu_bo) 335428d7b3dSmrg priv->pinned |= PIN_DRI3; 336428d7b3dSmrg list_move(&priv->cow_list, &sna->dri3.pixmaps); 337428d7b3dSmrg 338428d7b3dSmrg mark_dri3_pixmap(sna, priv, bo); 339428d7b3dSmrg 340428d7b3dSmrg *stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch; 341428d7b3dSmrg *size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo); 342428d7b3dSmrg DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n", 343428d7b3dSmrg __FUNCTION__, 344428d7b3dSmrg (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber, 345428d7b3dSmrg (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle, 346428d7b3dSmrg *stride, *size)); 347428d7b3dSmrg return fd; 348428d7b3dSmrg} 349428d7b3dSmrg 350428d7b3dSmrgstatic dri3_screen_info_rec sna_dri3_info = { 351428d7b3dSmrg .version = DRI3_SCREEN_INFO_VERSION, 352428d7b3dSmrg 353428d7b3dSmrg .open = sna_dri3_open_device, 354428d7b3dSmrg .pixmap_from_fd = sna_dri3_pixmap_from_fd, 355428d7b3dSmrg .fd_from_pixmap = sna_dri3_fd_from_pixmap, 356428d7b3dSmrg}; 357428d7b3dSmrg 358428d7b3dSmrgbool sna_dri3_open(struct sna *sna, ScreenPtr screen) 359428d7b3dSmrg{ 360428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 361428d7b3dSmrg 362428d7b3dSmrg if (!sna_sync_open(sna, screen)) 363428d7b3dSmrg return false; 364428d7b3dSmrg 365428d7b3dSmrg list_init(&sna->dri3.pixmaps); 366428d7b3dSmrg return dri3_screen_init(screen, &sna_dri3_info); 367428d7b3dSmrg} 368428d7b3dSmrg 369428d7b3dSmrgvoid sna_dri3_close(struct sna *sna, ScreenPtr screen) 370428d7b3dSmrg{ 371428d7b3dSmrg SyncScreenFuncsPtr funcs; 372428d7b3dSmrg 373428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 374428d7b3dSmrg 375428d7b3dSmrg funcs = miSyncGetScreenFuncs(screen); 376428d7b3dSmrg if (funcs) 377428d7b3dSmrg funcs->CreateFence = sna->dri3.create_fence; 378428d7b3dSmrg} 379