sna_dri3.c revision fe8aea9e
142542f5fSchristos/* 242542f5fSchristos * Copyright (c) 2014 Intel Corporation 342542f5fSchristos * 442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a 542542f5fSchristos * copy of this software and associated documentation files (the "Software"), 642542f5fSchristos * to deal in the Software without restriction, including without limitation 742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense, 842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the 942542f5fSchristos * Software is furnished to do so, subject to the following conditions: 1042542f5fSchristos * 1142542f5fSchristos * The above copyright notice and this permission notice (including the next 1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the 1342542f5fSchristos * Software. 1442542f5fSchristos * 1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2142542f5fSchristos * SOFTWARE. 2242542f5fSchristos * 2342542f5fSchristos */ 2442542f5fSchristos 2542542f5fSchristos#ifdef HAVE_CONFIG_H 2642542f5fSchristos#include "config.h" 2742542f5fSchristos#endif 2842542f5fSchristos 2942542f5fSchristos#include <sys/types.h> 3042542f5fSchristos#include <fcntl.h> 3142542f5fSchristos#include <unistd.h> 3242542f5fSchristos#include <errno.h> 3342542f5fSchristos#include <xf86drm.h> 3442542f5fSchristos 3542542f5fSchristos#include "sna.h" 3642542f5fSchristos 3742542f5fSchristos#include <xf86.h> 3842542f5fSchristos#include <dri3.h> 3942542f5fSchristos#include <misyncshm.h> 4042542f5fSchristos#include <misyncstr.h> 4142542f5fSchristos 4242542f5fSchristosstatic DevPrivateKeyRec sna_sync_fence_private_key; 4342542f5fSchristosstruct sna_sync_fence { 4442542f5fSchristos SyncFenceSetTriggeredFunc set_triggered; 4542542f5fSchristos}; 4642542f5fSchristos 4742542f5fSchristosstatic inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence) 4842542f5fSchristos{ 4942542f5fSchristos return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key); 5042542f5fSchristos} 5142542f5fSchristos 5213496ba1Ssnjstatic inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, struct kgem_bo *bo) 5313496ba1Ssnj{ 5413496ba1Ssnj bo->flush = true; 5513496ba1Ssnj if (bo->exec) 5613496ba1Ssnj sna->kgem.flush = 1; 5713496ba1Ssnj if (bo == priv->gpu_bo) 58fe8aea9eSmrg priv->flush |= FLUSH_READ | FLUSH_WRITE; 5913496ba1Ssnj else 6013496ba1Ssnj priv->shm = true; 6113496ba1Ssnj 62fe8aea9eSmrg sna_watch_flush(sna, 1); 63fe8aea9eSmrg 64fe8aea9eSmrg kgem_bo_submit(&sna->kgem, bo); 65fe8aea9eSmrg kgem_bo_unclean(&sna->kgem, bo); 6613496ba1Ssnj} 6713496ba1Ssnj 6842542f5fSchristosstatic void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv) 6942542f5fSchristos{ 7042542f5fSchristos struct kgem_bo *bo = NULL; 7142542f5fSchristos 7242542f5fSchristos DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 7342542f5fSchristos assert(priv); 7442542f5fSchristos 7542542f5fSchristos if (priv->pinned & PIN_DRI3) { 7642542f5fSchristos assert(priv->gpu_bo); 7742542f5fSchristos assert(priv->pinned & PIN_DRI3); 7842542f5fSchristos DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle)); 7942542f5fSchristos if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) { 8042542f5fSchristos sna_damage_all(&priv->gpu_damage, priv->pixmap); 8142542f5fSchristos bo = priv->gpu_bo; 8242542f5fSchristos } 8342542f5fSchristos } else { 8442542f5fSchristos assert(priv->cpu_bo); 8542542f5fSchristos assert(IS_STATIC_PTR(priv->ptr)); 8642542f5fSchristos DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle)); 8742542f5fSchristos if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 8842542f5fSchristos bo = priv->cpu_bo; 8942542f5fSchristos } 9042542f5fSchristos 9142542f5fSchristos if (bo != NULL) { 9242542f5fSchristos kgem_bo_submit(&sna->kgem, bo); 9342542f5fSchristos kgem_bo_unclean(&sna->kgem, bo); 9442542f5fSchristos } 9542542f5fSchristos} 9642542f5fSchristos 9742542f5fSchristosstatic void 9842542f5fSchristossna_sync_fence_set_triggered(SyncFence *fence) 9942542f5fSchristos{ 10042542f5fSchristos struct sna *sna = to_sna_from_screen(fence->pScreen); 10142542f5fSchristos struct sna_sync_fence *sna_fence = sna_sync_fence(fence); 10242542f5fSchristos 10342542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 10413496ba1Ssnj sna_accel_flush(sna); 10542542f5fSchristos 10642542f5fSchristos fence->funcs.SetTriggered = sna_fence->set_triggered; 10742542f5fSchristos sna_fence->set_triggered(fence); 10842542f5fSchristos sna_fence->set_triggered = fence->funcs.SetTriggered; 10942542f5fSchristos fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 11042542f5fSchristos} 11142542f5fSchristos 11242542f5fSchristosstatic void 11342542f5fSchristossna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered) 11442542f5fSchristos{ 11542542f5fSchristos struct sna *sna = to_sna_from_screen(screen); 11642542f5fSchristos SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen); 11742542f5fSchristos 11842542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 11942542f5fSchristos 12042542f5fSchristos funcs->CreateFence = sna->dri3.create_fence; 12142542f5fSchristos sna->dri3.create_fence(screen, fence, initially_triggered); 12242542f5fSchristos sna->dri3.create_fence = funcs->CreateFence; 12342542f5fSchristos funcs->CreateFence = sna_sync_create_fence; 12442542f5fSchristos 12542542f5fSchristos sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered; 12642542f5fSchristos fence->funcs.SetTriggered = sna_sync_fence_set_triggered; 12742542f5fSchristos} 12842542f5fSchristos 12942542f5fSchristosstatic bool 13042542f5fSchristossna_sync_open(struct sna *sna, ScreenPtr screen) 13142542f5fSchristos{ 13242542f5fSchristos SyncScreenFuncsPtr funcs; 13342542f5fSchristos 13442542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 13542542f5fSchristos 13642542f5fSchristos if (!miSyncShmScreenInit(screen)) 13742542f5fSchristos return false; 13842542f5fSchristos 13942542f5fSchristos if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) { 14042542f5fSchristos if (!dixRegisterPrivateKey(&sna_sync_fence_private_key, 14142542f5fSchristos PRIVATE_SYNC_FENCE, 14242542f5fSchristos sizeof(struct sna_sync_fence))) 14342542f5fSchristos return false; 14442542f5fSchristos } 14542542f5fSchristos 14642542f5fSchristos funcs = miSyncGetScreenFuncs(screen); 14742542f5fSchristos sna->dri3.create_fence = funcs->CreateFence; 14842542f5fSchristos funcs->CreateFence = sna_sync_create_fence; 14942542f5fSchristos 15042542f5fSchristos return true; 15142542f5fSchristos} 15242542f5fSchristos 15342542f5fSchristosstatic int sna_dri3_open_device(ScreenPtr screen, 15442542f5fSchristos RRProviderPtr provider, 15542542f5fSchristos int *out) 15642542f5fSchristos{ 15742542f5fSchristos int fd; 15842542f5fSchristos 15942542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 16013496ba1Ssnj fd = intel_get_client_fd(to_sna_from_screen(screen)->dev); 16142542f5fSchristos if (fd < 0) 16242542f5fSchristos return -fd; 16342542f5fSchristos 16442542f5fSchristos *out = fd; 16542542f5fSchristos return Success; 16642542f5fSchristos} 16742542f5fSchristos 16842542f5fSchristosstatic PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen, 16942542f5fSchristos int fd, 17042542f5fSchristos CARD16 width, 17142542f5fSchristos CARD16 height, 17242542f5fSchristos CARD16 stride, 17342542f5fSchristos CARD8 depth, 17442542f5fSchristos CARD8 bpp) 17542542f5fSchristos{ 17642542f5fSchristos struct sna *sna = to_sna_from_screen(screen); 17742542f5fSchristos PixmapPtr pixmap; 17842542f5fSchristos struct sna_pixmap *priv; 17942542f5fSchristos struct kgem_bo *bo; 18042542f5fSchristos 18142542f5fSchristos DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n", 18242542f5fSchristos __FUNCTION__, fd, width, height, stride, depth, bpp)); 18342542f5fSchristos if (width > INT16_MAX || height > INT16_MAX) 18442542f5fSchristos return NULL; 18542542f5fSchristos 18642542f5fSchristos if ((uint32_t)width * bpp > (uint32_t)stride * 8) 18742542f5fSchristos return NULL; 18842542f5fSchristos 18942542f5fSchristos if (depth < 8) 19042542f5fSchristos return NULL; 19142542f5fSchristos 19242542f5fSchristos switch (bpp) { 19342542f5fSchristos case 8: 19442542f5fSchristos case 16: 19542542f5fSchristos case 32: 19642542f5fSchristos break; 19742542f5fSchristos default: 19842542f5fSchristos return NULL; 19942542f5fSchristos } 20042542f5fSchristos 20142542f5fSchristos bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height); 20242542f5fSchristos if (bo == NULL) 20342542f5fSchristos return NULL; 20442542f5fSchristos 20542542f5fSchristos /* Check for a duplicate */ 20642542f5fSchristos list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) { 20742542f5fSchristos int other_stride = 0; 20842542f5fSchristos if (bo->snoop) { 20942542f5fSchristos assert(priv->cpu_bo); 21042542f5fSchristos assert(IS_STATIC_PTR(priv->ptr)); 21142542f5fSchristos if (bo->handle == priv->cpu_bo->handle) 21242542f5fSchristos other_stride = priv->cpu_bo->pitch; 21342542f5fSchristos } else { 21442542f5fSchristos assert(priv->gpu_bo); 21542542f5fSchristos assert(priv->pinned & PIN_DRI3); 21642542f5fSchristos if (bo->handle == priv->gpu_bo->handle) 21742542f5fSchristos other_stride = priv->gpu_bo->pitch; 21842542f5fSchristos } 21942542f5fSchristos if (other_stride) { 22042542f5fSchristos pixmap = priv->pixmap; 22142542f5fSchristos DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 22242542f5fSchristos bo->handle = 0; /* fudge to prevent gem_close */ 22342542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 22442542f5fSchristos if (width != pixmap->drawable.width || 22542542f5fSchristos height != pixmap->drawable.height || 22642542f5fSchristos depth != pixmap->drawable.depth || 22742542f5fSchristos bpp != pixmap->drawable.bitsPerPixel || 22842542f5fSchristos stride != other_stride) { 22942542f5fSchristos DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__, 23042542f5fSchristos pixmap->drawable.width, 23142542f5fSchristos pixmap->drawable.height, 23242542f5fSchristos pixmap->drawable.depth, 23342542f5fSchristos pixmap->drawable.bitsPerPixel, 23442542f5fSchristos other_stride)); 23542542f5fSchristos return NULL; 23642542f5fSchristos } 23742542f5fSchristos sna_sync_flush(sna, priv); 23842542f5fSchristos pixmap->refcnt++; 23942542f5fSchristos return pixmap; 24042542f5fSchristos } 24142542f5fSchristos } 24242542f5fSchristos 24342542f5fSchristos if (!kgem_check_surface_size(&sna->kgem, 24442542f5fSchristos width, height, bpp, 24542542f5fSchristos bo->tiling, stride, kgem_bo_size(bo))) { 24642542f5fSchristos DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n", 24742542f5fSchristos __FUNCTION__, stride, kgem_bo_size(bo), width, height)); 24842542f5fSchristos goto free_bo; 24942542f5fSchristos } 25042542f5fSchristos 25142542f5fSchristos pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 25242542f5fSchristos if (pixmap == NullPixmap) 25342542f5fSchristos goto free_bo; 25442542f5fSchristos 25542542f5fSchristos if (!screen->ModifyPixmapHeader(pixmap, width, height, 25642542f5fSchristos depth, bpp, stride, NULL)) 25742542f5fSchristos goto free_pixmap; 25842542f5fSchristos 25942542f5fSchristos priv = sna_pixmap_attach_to_bo(pixmap, bo); 26042542f5fSchristos if (priv == NULL) 26142542f5fSchristos goto free_pixmap; 26242542f5fSchristos 26342542f5fSchristos bo->pitch = stride; 26442542f5fSchristos priv->stride = stride; 26542542f5fSchristos 26642542f5fSchristos if (bo->snoop) { 26742542f5fSchristos assert(priv->cpu_bo == bo); 26842542f5fSchristos pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 26942542f5fSchristos if (pixmap->devPrivate.ptr == NULL) 27042542f5fSchristos goto free_pixmap; 27142542f5fSchristos 27242542f5fSchristos pixmap->devKind = stride; 27342542f5fSchristos priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 27442542f5fSchristos } else { 27542542f5fSchristos assert(priv->gpu_bo == bo); 276fe8aea9eSmrg priv->create = kgem_can_create_2d(&sna->kgem, 277fe8aea9eSmrg width, height, depth); 27842542f5fSchristos priv->pinned |= PIN_DRI3; 27942542f5fSchristos } 28042542f5fSchristos list_add(&priv->cow_list, &sna->dri3.pixmaps); 28142542f5fSchristos 28213496ba1Ssnj mark_dri3_pixmap(sna, priv, bo); 28313496ba1Ssnj 28442542f5fSchristos return pixmap; 28542542f5fSchristos 28642542f5fSchristosfree_pixmap: 28742542f5fSchristos screen->DestroyPixmap(pixmap); 28842542f5fSchristosfree_bo: 28942542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 29042542f5fSchristos return NULL; 29142542f5fSchristos} 29242542f5fSchristos 29342542f5fSchristosstatic int sna_dri3_fd_from_pixmap(ScreenPtr screen, 29442542f5fSchristos PixmapPtr pixmap, 29542542f5fSchristos CARD16 *stride, 29642542f5fSchristos CARD32 *size) 29742542f5fSchristos{ 29842542f5fSchristos struct sna *sna = to_sna_from_screen(screen); 29942542f5fSchristos struct sna_pixmap *priv; 30042542f5fSchristos struct kgem_bo *bo = NULL; 30142542f5fSchristos int fd; 30242542f5fSchristos 30342542f5fSchristos DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__, 30442542f5fSchristos pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 30542542f5fSchristos if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) { 30642542f5fSchristos DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__)); 30742542f5fSchristos return -1; 30842542f5fSchristos } 30942542f5fSchristos 31042542f5fSchristos priv = sna_pixmap(pixmap); 31142542f5fSchristos if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { 31242542f5fSchristos if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) 31342542f5fSchristos bo = priv->cpu_bo; 31442542f5fSchristos } else { 31542542f5fSchristos priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI); 31642542f5fSchristos if (priv != NULL) { 31742542f5fSchristos sna_damage_all(&priv->gpu_damage, pixmap); 31842542f5fSchristos bo = priv->gpu_bo; 31942542f5fSchristos } 32042542f5fSchristos } 32142542f5fSchristos if (bo == NULL) { 32242542f5fSchristos DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__)); 32342542f5fSchristos return -1; 32442542f5fSchristos } 32542542f5fSchristos assert(priv != NULL); 32642542f5fSchristos 32742542f5fSchristos if (bo->pitch > UINT16_MAX) { 32842542f5fSchristos DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n", 32942542f5fSchristos __FUNCTION__, bo->pitch)); 33042542f5fSchristos return -1; 33142542f5fSchristos } 33242542f5fSchristos 333fe8aea9eSmrg if (bo->tiling && !sna->kgem.can_fence) { 334fe8aea9eSmrg if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) { 335fe8aea9eSmrg DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n", 336fe8aea9eSmrg __FUNCTION__, bo->tiling)); 337fe8aea9eSmrg return -1; 338fe8aea9eSmrg } 339fe8aea9eSmrg bo = priv->gpu_bo; 340fe8aea9eSmrg } 341fe8aea9eSmrg 34242542f5fSchristos fd = kgem_bo_export_to_prime(&sna->kgem, bo); 34342542f5fSchristos if (fd == -1) { 34442542f5fSchristos DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle)); 34542542f5fSchristos return -1; 34642542f5fSchristos } 34742542f5fSchristos 34842542f5fSchristos if (bo == priv->gpu_bo) 34942542f5fSchristos priv->pinned |= PIN_DRI3; 35042542f5fSchristos list_move(&priv->cow_list, &sna->dri3.pixmaps); 35142542f5fSchristos 35213496ba1Ssnj mark_dri3_pixmap(sna, priv, bo); 35313496ba1Ssnj 35442542f5fSchristos *stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch; 35542542f5fSchristos *size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo); 35642542f5fSchristos DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n", 35742542f5fSchristos __FUNCTION__, 35842542f5fSchristos (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber, 35942542f5fSchristos (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle, 36042542f5fSchristos *stride, *size)); 36142542f5fSchristos return fd; 36242542f5fSchristos} 36342542f5fSchristos 36442542f5fSchristosstatic dri3_screen_info_rec sna_dri3_info = { 36542542f5fSchristos .version = DRI3_SCREEN_INFO_VERSION, 36642542f5fSchristos 36742542f5fSchristos .open = sna_dri3_open_device, 36842542f5fSchristos .pixmap_from_fd = sna_dri3_pixmap_from_fd, 36942542f5fSchristos .fd_from_pixmap = sna_dri3_fd_from_pixmap, 37042542f5fSchristos}; 37142542f5fSchristos 37242542f5fSchristosbool sna_dri3_open(struct sna *sna, ScreenPtr screen) 37342542f5fSchristos{ 37442542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 37542542f5fSchristos 37642542f5fSchristos if (!sna_sync_open(sna, screen)) 37742542f5fSchristos return false; 37842542f5fSchristos 37942542f5fSchristos list_init(&sna->dri3.pixmaps); 38042542f5fSchristos return dri3_screen_init(screen, &sna_dri3_info); 38142542f5fSchristos} 38242542f5fSchristos 38342542f5fSchristosvoid sna_dri3_close(struct sna *sna, ScreenPtr screen) 38442542f5fSchristos{ 38542542f5fSchristos SyncScreenFuncsPtr funcs; 38642542f5fSchristos 38742542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 38842542f5fSchristos 38942542f5fSchristos funcs = miSyncGetScreenFuncs(screen); 39042542f5fSchristos if (funcs) 39142542f5fSchristos funcs->CreateFence = sna->dri3.create_fence; 39242542f5fSchristos} 393