142542f5fSchristos/************************************************************************** 242542f5fSchristos 342542f5fSchristosCopyright 2001 VA Linux Systems Inc., Fremont, California. 442542f5fSchristosCopyright © 2002 by David Dawes 542542f5fSchristos 642542f5fSchristosAll Rights Reserved. 742542f5fSchristos 842542f5fSchristosPermission is hereby granted, free of charge, to any person obtaining a 942542f5fSchristoscopy of this software and associated documentation files (the "Software"), 1042542f5fSchristosto deal in the Software without restriction, including without limitation 1142542f5fSchristoson the rights to use, copy, modify, merge, publish, distribute, sub 1242542f5fSchristoslicense, and/or sell copies of the Software, and to permit persons to whom 1342542f5fSchristosthe Software is furnished to do so, subject to the following conditions: 1442542f5fSchristos 1542542f5fSchristosThe above copyright notice and this permission notice (including the next 1642542f5fSchristosparagraph) shall be included in all copies or substantial portions of the 1742542f5fSchristosSoftware. 1842542f5fSchristos 1942542f5fSchristosTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2042542f5fSchristosIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2142542f5fSchristosFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2242542f5fSchristosATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 2342542f5fSchristosDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2442542f5fSchristosOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2542542f5fSchristosUSE OR OTHER DEALINGS IN THE SOFTWARE. 2642542f5fSchristos 2742542f5fSchristos**************************************************************************/ 2842542f5fSchristos 2942542f5fSchristos/* 3042542f5fSchristos * Authors: Jeff Hartmann <jhartmann@valinux.com> 3142542f5fSchristos * David Dawes <dawes@xfree86.org> 3242542f5fSchristos * Keith Whitwell <keith@tungstengraphics.com> 3342542f5fSchristos */ 3442542f5fSchristos 3542542f5fSchristos#ifdef HAVE_CONFIG_H 3642542f5fSchristos#include "config.h" 3742542f5fSchristos#endif 3842542f5fSchristos 3942542f5fSchristos#include <errno.h> 4042542f5fSchristos#include <time.h> 4142542f5fSchristos#include <string.h> 4242542f5fSchristos#include <unistd.h> 4342542f5fSchristos#include <poll.h> 4442542f5fSchristos 4542542f5fSchristos#include "sna.h" 4642542f5fSchristos#include "intel_options.h" 4742542f5fSchristos 4842542f5fSchristos#include <xf86drm.h> 4942542f5fSchristos#include <i915_drm.h> 5042542f5fSchristos#include <dri2.h> 5142542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) && defined(COMPOSITE) 5242542f5fSchristos#include <compositeext.h> 5342542f5fSchristos#define CHECK_FOR_COMPOSITOR 5442542f5fSchristos#endif 5542542f5fSchristos 5642542f5fSchristos#define DBG_CAN_FLIP 1 5742542f5fSchristos#define DBG_CAN_XCHG 1 5842542f5fSchristos 5942542f5fSchristos#define DBG_FORCE_COPY -1 /* KGEM_BLT or KGEM_3D */ 6042542f5fSchristos 6142542f5fSchristos#if DRI2INFOREC_VERSION < 2 6242542f5fSchristos#error DRI2 version supported by the Xserver is too old 6342542f5fSchristos#endif 6442542f5fSchristos 6542542f5fSchristosstatic inline struct kgem_bo *ref(struct kgem_bo *bo) 6642542f5fSchristos{ 6713496ba1Ssnj return kgem_bo_reference(bo); 6842542f5fSchristos} 6942542f5fSchristos 7042542f5fSchristosstruct sna_dri2_private { 7142542f5fSchristos PixmapPtr pixmap; 7242542f5fSchristos struct kgem_bo *bo; 7342542f5fSchristos DRI2Buffer2Ptr proxy; 7442542f5fSchristos bool stale; 7542542f5fSchristos uint32_t size; 7642542f5fSchristos int refcnt; 7742542f5fSchristos}; 7842542f5fSchristos 7942542f5fSchristosstatic inline struct sna_dri2_private * 8042542f5fSchristosget_private(void *buffer) 8142542f5fSchristos{ 8242542f5fSchristos return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1); 8342542f5fSchristos} 8442542f5fSchristos 8563ef14f0Smrgpure static inline DRI2BufferPtr sna_pixmap_get_buffer(PixmapPtr pixmap) 8663ef14f0Smrg{ 8763ef14f0Smrg assert(pixmap->refcnt); 8863ef14f0Smrg return ((void **)__get_private(pixmap, sna_pixmap_key))[2]; 8963ef14f0Smrg} 9063ef14f0Smrg 9163ef14f0Smrgstatic inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr) 9263ef14f0Smrg{ 9363ef14f0Smrg assert(pixmap->refcnt); 9463ef14f0Smrg ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr; 9563ef14f0Smrg} 9663ef14f0Smrg 9742542f5fSchristos#if DRI2INFOREC_VERSION >= 4 9842542f5fSchristosenum event_type { 9942542f5fSchristos WAITMSC = 0, 10042542f5fSchristos SWAP, 10163ef14f0Smrg SWAP_COMPLETE, 10242542f5fSchristos FLIP, 10342542f5fSchristos FLIP_THROTTLE, 10442542f5fSchristos FLIP_COMPLETE, 10542542f5fSchristos FLIP_ASYNC, 10642542f5fSchristos}; 10742542f5fSchristos 10842542f5fSchristosstruct dri_bo { 10942542f5fSchristos struct list link; 11042542f5fSchristos struct kgem_bo *bo; 11142542f5fSchristos uint32_t name; 11263ef14f0Smrg unsigned flags; 11342542f5fSchristos}; 11442542f5fSchristos 11542542f5fSchristosstruct sna_dri2_event { 11613496ba1Ssnj struct sna *sna; 11742542f5fSchristos DrawablePtr draw; 11842542f5fSchristos ClientPtr client; 11942542f5fSchristos enum event_type type; 12042542f5fSchristos xf86CrtcPtr crtc; 12142542f5fSchristos int pipe; 12242542f5fSchristos bool queued; 12363ef14f0Smrg bool sync; 12463ef14f0Smrg bool chained; 12542542f5fSchristos 12642542f5fSchristos /* for swaps & flips only */ 12742542f5fSchristos DRI2SwapEventPtr event_complete; 12842542f5fSchristos void *event_data; 12942542f5fSchristos DRI2BufferPtr front; 13042542f5fSchristos DRI2BufferPtr back; 13142542f5fSchristos struct kgem_bo *bo; 13242542f5fSchristos 13363ef14f0Smrg struct copy { 13463ef14f0Smrg struct kgem_bo *bo; 13563ef14f0Smrg unsigned flags; 13663ef14f0Smrg uint32_t name; 13763ef14f0Smrg uint32_t size; 13863ef14f0Smrg } pending; 13963ef14f0Smrg 14042542f5fSchristos struct sna_dri2_event *chain; 14142542f5fSchristos 14242542f5fSchristos struct list link; 14342542f5fSchristos 14463ef14f0Smrg int flip_continue; 14563ef14f0Smrg int keepalive; 14663ef14f0Smrg int signal; 14742542f5fSchristos}; 14842542f5fSchristos 14963ef14f0Smrg#if DRI2INFOREC_VERSION < 10 15063ef14f0Smrg#undef USE_ASYNC_SWAP 15163ef14f0Smrg#endif 15263ef14f0Smrg 15363ef14f0Smrg#if USE_ASYNC_SWAP 15463ef14f0Smrg#define KEEPALIVE 8 /* wait ~100ms before discarding swap caches */ 15563ef14f0Smrg#define APPLY_DAMAGE 0 15663ef14f0Smrg#else 15763ef14f0Smrg#define USE_ASYNC_SWAP 0 15863ef14f0Smrg#define KEEPALIVE 1 15963ef14f0Smrg#define APPLY_DAMAGE 1 16063ef14f0Smrg#endif 16163ef14f0Smrg 16213496ba1Ssnjstatic void sna_dri2_flip_event(struct sna_dri2_event *flip); 16363ef14f0Smrginline static DRI2BufferPtr dri2_window_get_front(WindowPtr win); 16463ef14f0Smrg 16563ef14f0Smrgstatic struct kgem_bo * 16663ef14f0Smrg__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region, 16763ef14f0Smrg DRI2BufferPtr src, DRI2BufferPtr dst, 16863ef14f0Smrg unsigned flags); 16963ef14f0Smrg 17063ef14f0Smrginline static void 17163ef14f0Smrg__sna_dri2_copy_event(struct sna_dri2_event *info, unsigned flags) 17263ef14f0Smrg{ 17363ef14f0Smrg DBG(("%s: flags = %x\n", __FUNCTION__, flags)); 17463ef14f0Smrg assert(info->front != info->back); 17563ef14f0Smrg info->bo = __sna_dri2_copy_region(info->sna, info->draw, NULL, 17663ef14f0Smrg info->back, info->front, 17763ef14f0Smrg flags); 17863ef14f0Smrg info->front->flags = info->back->flags; 17963ef14f0Smrg} 18063ef14f0Smrg 18163ef14f0Smrgstatic int front_pitch(DrawablePtr draw) 18263ef14f0Smrg{ 18363ef14f0Smrg DRI2BufferPtr buffer; 18463ef14f0Smrg 18563ef14f0Smrg buffer = NULL; 18663ef14f0Smrg if (draw->type != DRAWABLE_PIXMAP) 18763ef14f0Smrg buffer = dri2_window_get_front((WindowPtr)draw); 18863ef14f0Smrg if (buffer == NULL) 18963ef14f0Smrg buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw)); 19063ef14f0Smrg 19163ef14f0Smrg return buffer ? buffer->pitch : 0; 19263ef14f0Smrg} 19363ef14f0Smrg 19463ef14f0Smrgstruct dri2_window { 19563ef14f0Smrg DRI2BufferPtr front; 19663ef14f0Smrg struct sna_dri2_event *chain; 19763ef14f0Smrg xf86CrtcPtr crtc; 19863ef14f0Smrg int64_t msc_delta; 19963ef14f0Smrg struct list cache; 20063ef14f0Smrg uint32_t cache_size; 20163ef14f0Smrg}; 20263ef14f0Smrg 20363ef14f0Smrgstatic struct dri2_window *dri2_window(WindowPtr win) 20463ef14f0Smrg{ 20563ef14f0Smrg assert(win->drawable.type != DRAWABLE_PIXMAP); 20663ef14f0Smrg return ((void **)__get_private(win, sna_window_key))[1]; 20763ef14f0Smrg} 20863ef14f0Smrg 20963ef14f0Smrgstatic bool use_scanout(struct sna *sna, 21063ef14f0Smrg DrawablePtr draw, 21163ef14f0Smrg struct dri2_window *priv) 21263ef14f0Smrg{ 21363ef14f0Smrg if (priv->front) 21463ef14f0Smrg return true; 21563ef14f0Smrg 21663ef14f0Smrg return (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0 && 21763ef14f0Smrg draw->width == sna->front->drawable.width && 21863ef14f0Smrg draw->height == sna->front->drawable.height && 21963ef14f0Smrg draw->bitsPerPixel == sna->front->drawable.bitsPerPixel; 22063ef14f0Smrg} 22142542f5fSchristos 22242542f5fSchristosstatic void 22342542f5fSchristossna_dri2_get_back(struct sna *sna, 22442542f5fSchristos DrawablePtr draw, 22563ef14f0Smrg DRI2BufferPtr back) 22642542f5fSchristos{ 22763ef14f0Smrg struct dri2_window *priv = dri2_window((WindowPtr)draw); 22863ef14f0Smrg uint32_t size; 22942542f5fSchristos struct kgem_bo *bo; 23063ef14f0Smrg struct dri_bo *c; 23142542f5fSchristos uint32_t name; 23263ef14f0Smrg int flags; 23342542f5fSchristos bool reuse; 23442542f5fSchristos 23563ef14f0Smrg DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, active?=%d, pitch=%d, front pitch=%d\n", 23642542f5fSchristos __FUNCTION__, draw->width, draw->height, 23763ef14f0Smrg get_private(back)->bo->handle, 23863ef14f0Smrg get_private(back)->size & 0xffff, get_private(back)->size >> 16, 23963ef14f0Smrg get_private(back)->bo->scanout, 24063ef14f0Smrg get_private(back)->bo->active_scanout, 24163ef14f0Smrg back->pitch, front_pitch(draw))); 24263ef14f0Smrg assert(priv); 24363ef14f0Smrg 24463ef14f0Smrg size = draw->height << 16 | draw->width; 24563ef14f0Smrg if (size != priv->cache_size) { 24663ef14f0Smrg while (!list_is_empty(&priv->cache)) { 24763ef14f0Smrg c = list_first_entry(&priv->cache, struct dri_bo, link); 24863ef14f0Smrg list_del(&c->link); 24963ef14f0Smrg 25063ef14f0Smrg DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0)); 25163ef14f0Smrg assert(c->bo); 25263ef14f0Smrg kgem_bo_destroy(&sna->kgem, c->bo); 25363ef14f0Smrg 25463ef14f0Smrg free(c); 25563ef14f0Smrg } 25663ef14f0Smrg priv->cache_size = size; 25763ef14f0Smrg } 25863ef14f0Smrg 25963ef14f0Smrg reuse = size == get_private(back)->size; 26063ef14f0Smrg if (reuse) 26163ef14f0Smrg reuse = get_private(back)->bo->scanout == use_scanout(sna, draw, priv); 26263ef14f0Smrg DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse)); 26342542f5fSchristos if (reuse) { 26442542f5fSchristos bo = get_private(back)->bo; 26542542f5fSchristos assert(bo->refcnt); 26663ef14f0Smrg DBG(("%s: back buffer handle=%d, active?=%d, refcnt=%d\n", 26763ef14f0Smrg __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt)); 26842542f5fSchristos if (bo->active_scanout == 0) { 26942542f5fSchristos DBG(("%s: reuse unattached back\n", __FUNCTION__)); 27042542f5fSchristos get_private(back)->stale = false; 27142542f5fSchristos return; 27242542f5fSchristos } 27342542f5fSchristos } 27442542f5fSchristos 27542542f5fSchristos bo = NULL; 27663ef14f0Smrg list_for_each_entry(c, &priv->cache, link) { 27763ef14f0Smrg DBG(("%s: cache: handle=%d, active=%d\n", 27863ef14f0Smrg __FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1)); 27963ef14f0Smrg assert(c->bo); 28063ef14f0Smrg if (c->bo->active_scanout == 0) { 28163ef14f0Smrg _list_del(&c->link); 28263ef14f0Smrg if (c->bo == NULL) { 28363ef14f0Smrg free(c); 28463ef14f0Smrg goto out; 28542542f5fSchristos } 28663ef14f0Smrg bo = c->bo; 28763ef14f0Smrg name = c->name; 28863ef14f0Smrg flags = c->flags; 28963ef14f0Smrg DBG(("%s: reuse cache handle=%d, name=%d, flags=%d\n", __FUNCTION__, bo->handle, name, flags)); 29063ef14f0Smrg c->bo = NULL; 29163ef14f0Smrg break; 29242542f5fSchristos } 29342542f5fSchristos } 29442542f5fSchristos if (bo == NULL) { 29542542f5fSchristos DBG(("%s: allocating new backbuffer\n", __FUNCTION__)); 29663ef14f0Smrg flags = CREATE_EXACT; 29763ef14f0Smrg 29863ef14f0Smrg if (get_private(back)->bo->scanout && 29963ef14f0Smrg use_scanout(sna, draw, priv)) { 30063ef14f0Smrg DBG(("%s: requesting scanout compatible back\n", __FUNCTION__)); 30163ef14f0Smrg flags |= CREATE_SCANOUT; 30263ef14f0Smrg } 30363ef14f0Smrg 30442542f5fSchristos bo = kgem_create_2d(&sna->kgem, 30542542f5fSchristos draw->width, draw->height, draw->bitsPerPixel, 30642542f5fSchristos get_private(back)->bo->tiling, 30763ef14f0Smrg flags); 30842542f5fSchristos if (bo == NULL) 30942542f5fSchristos return; 31042542f5fSchristos 31142542f5fSchristos name = kgem_bo_flink(&sna->kgem, bo); 31242542f5fSchristos if (name == 0) { 31342542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 31442542f5fSchristos return; 31542542f5fSchristos } 31663ef14f0Smrg 31763ef14f0Smrg flags = 0; 31863ef14f0Smrg if (USE_ASYNC_SWAP && back->flags) { 31963ef14f0Smrg BoxRec box; 32063ef14f0Smrg 32163ef14f0Smrg box.x1 = 0; 32263ef14f0Smrg box.y1 = 0; 32363ef14f0Smrg box.x2 = draw->width; 32463ef14f0Smrg box.y2 = draw->height; 32563ef14f0Smrg 32663ef14f0Smrg DBG(("%s: filling new buffer with old back\n", __FUNCTION__)); 32763ef14f0Smrg if (sna->render.copy_boxes(sna, GXcopy, 32863ef14f0Smrg draw, get_private(back)->bo, 0, 0, 32963ef14f0Smrg draw, bo, 0, 0, 33063ef14f0Smrg &box, 1, COPY_LAST | COPY_DRI)) 33163ef14f0Smrg flags = back->flags; 33263ef14f0Smrg } 33342542f5fSchristos } 33442542f5fSchristos assert(bo->active_scanout == 0); 33542542f5fSchristos 33663ef14f0Smrg if (reuse && get_private(back)->bo->refcnt == 1 + get_private(back)->bo->active_scanout) { 33763ef14f0Smrg if (&c->link == &priv->cache) 33842542f5fSchristos c = malloc(sizeof(*c)); 33942542f5fSchristos if (c != NULL) { 34042542f5fSchristos c->bo = ref(get_private(back)->bo); 34142542f5fSchristos c->name = back->name; 34263ef14f0Smrg c->flags = back->flags; 34363ef14f0Smrg list_add(&c->link, &priv->cache); 34463ef14f0Smrg DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, c->bo->handle, c->name, c->flags, c->bo->active_scanout)); 34542542f5fSchristos } 34663ef14f0Smrg } else { 34763ef14f0Smrg if (&c->link != &priv->cache) 34863ef14f0Smrg free(c); 34942542f5fSchristos } 35042542f5fSchristos 35163ef14f0Smrg assert(bo->active_scanout == 0); 35242542f5fSchristos assert(bo != get_private(back)->bo); 35342542f5fSchristos kgem_bo_destroy(&sna->kgem, get_private(back)->bo); 35442542f5fSchristos 35542542f5fSchristos get_private(back)->bo = bo; 35642542f5fSchristos get_private(back)->size = draw->height << 16 | draw->width; 35742542f5fSchristos back->pitch = bo->pitch; 35842542f5fSchristos back->name = name; 35963ef14f0Smrg back->flags = flags; 36042542f5fSchristos 36163ef14f0Smrg assert(back->pitch); 36263ef14f0Smrg assert(back->name); 36342542f5fSchristos 36463ef14f0Smrgout: 36563ef14f0Smrg get_private(back)->stale = false; 36642542f5fSchristos} 36742542f5fSchristos 36842542f5fSchristosstatic struct sna_dri2_event * 36942542f5fSchristosdri2_chain(DrawablePtr d) 37042542f5fSchristos{ 37142542f5fSchristos struct dri2_window *priv = dri2_window((WindowPtr)d); 37242542f5fSchristos assert(priv != NULL); 37363ef14f0Smrg assert(priv->chain == NULL || priv->chain->chained); 37442542f5fSchristos return priv->chain; 37542542f5fSchristos} 37613496ba1Ssnjinline static DRI2BufferPtr dri2_window_get_front(WindowPtr win) 37713496ba1Ssnj{ 37813496ba1Ssnj struct dri2_window *priv = dri2_window(win); 37963ef14f0Smrg assert(priv->front == NULL || get_private(priv->front)->bo->active_scanout); 38013496ba1Ssnj return priv ? priv->front : NULL; 38113496ba1Ssnj} 38242542f5fSchristos#else 38342542f5fSchristosinline static void *dri2_window_get_front(WindowPtr win) { return NULL; } 38463ef14f0Smrg#define APPLY_DAMAGE 1 38542542f5fSchristos#endif 38642542f5fSchristos 38742542f5fSchristos#if DRI2INFOREC_VERSION < 6 38842542f5fSchristos 38913496ba1Ssnj#define xorg_can_triple_buffer() 0 39042542f5fSchristos#define swap_limit(d, l) false 391cbdaa46fSsnj#define mark_stale(b) 39242542f5fSchristos 39342542f5fSchristos#else 39442542f5fSchristos 39542542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,904,0) 39642542f5fSchristos/* Prime fixed for triple buffer support */ 39713496ba1Ssnj#define xorg_can_triple_buffer() 1 39842542f5fSchristos#elif XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,12,99,901,0) 39942542f5fSchristos/* Before numGPUScreens was introduced */ 40013496ba1Ssnj#define xorg_can_triple_buffer() 1 40142542f5fSchristos#else 40242542f5fSchristos/* Subject to crashers when combining triple buffering and Prime */ 40313496ba1Ssnjinline static bool xorg_can_triple_buffer(void) 40442542f5fSchristos{ 40542542f5fSchristos return screenInfo.numGPUScreens == 0; 40642542f5fSchristos} 40742542f5fSchristos#endif 40842542f5fSchristos 40913496ba1Ssnjstatic void 41013496ba1Ssnjmark_stale(DRI2BufferPtr back) 41113496ba1Ssnj{ 41213496ba1Ssnj /* If we have reuse notifications, we can track when the 41313496ba1Ssnj * client tries to present an old buffer (one that has not 41413496ba1Ssnj * been updated since the last swap) and avoid showing the 41513496ba1Ssnj * stale frame. (This is mostly useful for tracking down 41613496ba1Ssnj * driver bugs!) 41713496ba1Ssnj */ 41863ef14f0Smrg DBG(("%s(handle=%d) => %d\n", __FUNCTION__, 41963ef14f0Smrg get_private(back)->bo->handle, xorg_can_triple_buffer())); 42013496ba1Ssnj get_private(back)->stale = xorg_can_triple_buffer(); 42113496ba1Ssnj} 42213496ba1Ssnj 42342542f5fSchristosstatic Bool 42442542f5fSchristossna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit) 42542542f5fSchristos{ 42642542f5fSchristos DBG(("%s: swap limit set to %d\n", __FUNCTION__, swap_limit)); 42742542f5fSchristos return swap_limit >= 1; 42842542f5fSchristos} 42942542f5fSchristos 43042542f5fSchristosstatic void 43142542f5fSchristossna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer) 43242542f5fSchristos{ 43363ef14f0Smrg struct sna *sna = to_sna_from_drawable(draw); 43463ef14f0Smrg 43542542f5fSchristos DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n", 43642542f5fSchristos __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber, 43742542f5fSchristos buffer->attachment, get_private(buffer)->bo->handle, buffer->name)); 43842542f5fSchristos assert(get_private(buffer)->refcnt); 43963ef14f0Smrg assert(get_private(buffer)->bo->refcnt >= get_private(buffer)->bo->active_scanout); 44063ef14f0Smrg assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name); 44142542f5fSchristos 44242542f5fSchristos if (buffer->attachment == DRI2BufferBackLeft && 44342542f5fSchristos draw->type != DRAWABLE_PIXMAP) { 44463ef14f0Smrg DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id)); 44563ef14f0Smrg sna_dri2_get_back(sna, draw, buffer); 44642542f5fSchristos 44742542f5fSchristos assert(get_private(buffer)->bo->refcnt); 44842542f5fSchristos assert(get_private(buffer)->bo->active_scanout == 0); 44963ef14f0Smrg assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name); 45063ef14f0Smrg DBG(("%s: reusing back buffer handle=%d, name=%d, pitch=%d, age=%d\n", 45163ef14f0Smrg __FUNCTION__, get_private(buffer)->bo->handle, 45263ef14f0Smrg buffer->name, buffer->pitch, buffer->flags)); 45342542f5fSchristos } 45463ef14f0Smrg 45563ef14f0Smrg kgem_bo_submit(&sna->kgem, get_private(buffer)->bo); 45642542f5fSchristos} 45742542f5fSchristos 45842542f5fSchristosstatic bool swap_limit(DrawablePtr draw, int limit) 45942542f5fSchristos{ 46013496ba1Ssnj if (!xorg_can_triple_buffer()) 46113496ba1Ssnj return false; 46213496ba1Ssnj 46342542f5fSchristos DBG(("%s: draw=%ld setting swap limit to %d\n", __FUNCTION__, (long)draw->id, limit)); 46442542f5fSchristos DRI2SwapLimit(draw, limit); 46542542f5fSchristos return true; 46642542f5fSchristos} 46742542f5fSchristos#endif 46842542f5fSchristos 46942542f5fSchristos#define COLOR_PREFER_TILING_Y 0 47042542f5fSchristos 47142542f5fSchristos/* Prefer to enable TILING_Y if this buffer will never be a 47242542f5fSchristos * candidate for pageflipping 47342542f5fSchristos */ 47442542f5fSchristosstatic uint32_t color_tiling(struct sna *sna, DrawablePtr draw) 47542542f5fSchristos{ 47642542f5fSchristos uint32_t tiling; 47742542f5fSchristos 47863ef14f0Smrg if (!sna->kgem.can_fence) 47963ef14f0Smrg return I915_TILING_NONE; 48063ef14f0Smrg 48142542f5fSchristos if (COLOR_PREFER_TILING_Y && 48242542f5fSchristos (draw->width != sna->front->drawable.width || 48342542f5fSchristos draw->height != sna->front->drawable.height)) 48442542f5fSchristos tiling = I915_TILING_Y; 48542542f5fSchristos else 48642542f5fSchristos tiling = I915_TILING_X; 48742542f5fSchristos 48842542f5fSchristos return kgem_choose_tiling(&sna->kgem, -tiling, 48942542f5fSchristos draw->width, 49042542f5fSchristos draw->height, 49142542f5fSchristos draw->bitsPerPixel); 49242542f5fSchristos} 49342542f5fSchristos 49442542f5fSchristosstatic uint32_t other_tiling(struct sna *sna, DrawablePtr draw) 49542542f5fSchristos{ 49642542f5fSchristos /* XXX Can mix color X / depth Y? */ 49742542f5fSchristos return kgem_choose_tiling(&sna->kgem, 49842542f5fSchristos sna->kgem.gen >= 040 ? -I915_TILING_Y : -I915_TILING_X, 49942542f5fSchristos draw->width, 50042542f5fSchristos draw->height, 50142542f5fSchristos draw->bitsPerPixel); 50242542f5fSchristos} 50342542f5fSchristos 50442542f5fSchristosstatic struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, 50542542f5fSchristos PixmapPtr pixmap) 50642542f5fSchristos{ 50742542f5fSchristos struct sna_pixmap *priv; 50842542f5fSchristos 50942542f5fSchristos DBG(("%s: attaching DRI client to pixmap=%ld\n", 51042542f5fSchristos __FUNCTION__, pixmap->drawable.serialNumber)); 51142542f5fSchristos 51242542f5fSchristos priv = sna_pixmap(pixmap); 51342542f5fSchristos if (priv != NULL && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { 51442542f5fSchristos DBG(("%s: SHM or unattached Pixmap, BadAlloc\n", __FUNCTION__)); 51542542f5fSchristos return NULL; 51642542f5fSchristos } 51742542f5fSchristos 51842542f5fSchristos priv = sna_pixmap_move_to_gpu(pixmap, 51942542f5fSchristos MOVE_READ | __MOVE_FORCE | __MOVE_DRI); 52042542f5fSchristos if (priv == NULL) { 52142542f5fSchristos DBG(("%s: failed to move to GPU, BadAlloc\n", __FUNCTION__)); 52242542f5fSchristos return NULL; 52342542f5fSchristos } 52442542f5fSchristos 52563ef14f0Smrg assert(priv->flush == false || priv->pinned & PIN_DRI3); 52663ef14f0Smrg assert(priv->gpu_bo->flush == false || priv->pinned & PIN_DRI3); 52742542f5fSchristos assert(priv->cpu_damage == NULL); 52842542f5fSchristos assert(priv->gpu_bo); 52942542f5fSchristos assert(priv->gpu_bo->proxy == NULL); 53042542f5fSchristos 53163ef14f0Smrg if (!kgem_bo_is_fenced(&sna->kgem, priv->gpu_bo)) { 53263ef14f0Smrg if (priv->gpu_bo->tiling && 53363ef14f0Smrg !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) { 53463ef14f0Smrg DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling)); 53563ef14f0Smrg return NULL; 53663ef14f0Smrg } 53763ef14f0Smrg } else { 53863ef14f0Smrg int tiling = color_tiling(sna, &pixmap->drawable); 53963ef14f0Smrg if (tiling < 0) 54063ef14f0Smrg tiling = -tiling; 54163ef14f0Smrg if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout) 54263ef14f0Smrg sna_pixmap_change_tiling(pixmap, tiling); 54363ef14f0Smrg } 54442542f5fSchristos 54563ef14f0Smrg priv->gpu_bo->active_scanout++; 54642542f5fSchristos 54763ef14f0Smrg return priv->gpu_bo; 54842542f5fSchristos} 54942542f5fSchristos 55042542f5fSchristosvoid 55142542f5fSchristossna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo) 55242542f5fSchristos{ 55342542f5fSchristos DRI2BufferPtr buffer; 55442542f5fSchristos struct sna_dri2_private *private; 55542542f5fSchristos 55642542f5fSchristos buffer = sna_pixmap_get_buffer(pixmap); 55742542f5fSchristos if (buffer == NULL) 55842542f5fSchristos return; 55942542f5fSchristos 56042542f5fSchristos DBG(("%s: pixmap=%ld, old handle=%d, new handle=%d\n", __FUNCTION__, 56142542f5fSchristos pixmap->drawable.serialNumber, 56242542f5fSchristos get_private(buffer)->bo->handle, 56342542f5fSchristos sna_pixmap(pixmap)->gpu_bo->handle)); 56442542f5fSchristos 56542542f5fSchristos private = get_private(buffer); 56642542f5fSchristos assert(private->pixmap == pixmap); 56742542f5fSchristos 56842542f5fSchristos assert(bo != private->bo); 56942542f5fSchristos if (private->bo == bo) 57042542f5fSchristos return; 57142542f5fSchristos 57263ef14f0Smrg assert(private->bo->active_scanout > 0); 57363ef14f0Smrg private->bo->active_scanout--; 57463ef14f0Smrg 57542542f5fSchristos DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle)); 57642542f5fSchristos private->bo->flush = false; 57742542f5fSchristos kgem_bo_destroy(&sna->kgem, private->bo); 57842542f5fSchristos 57963ef14f0Smrg 58042542f5fSchristos buffer->name = kgem_bo_flink(&sna->kgem, bo); 58113496ba1Ssnj buffer->pitch = bo->pitch; 58242542f5fSchristos private->bo = ref(bo); 58363ef14f0Smrg bo->active_scanout++; 58442542f5fSchristos 58542542f5fSchristos DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle)); 58642542f5fSchristos bo->flush = true; 58713496ba1Ssnj if (bo->exec) 58813496ba1Ssnj sna->kgem.flush = 1; 58942542f5fSchristos assert(sna_pixmap(pixmap)->flush); 59042542f5fSchristos 59142542f5fSchristos /* XXX DRI2InvalidateDrawable(&pixmap->drawable); */ 59242542f5fSchristos} 59342542f5fSchristos 59442542f5fSchristosstatic DRI2Buffer2Ptr 59542542f5fSchristossna_dri2_create_buffer(DrawablePtr draw, 59642542f5fSchristos unsigned int attachment, 59742542f5fSchristos unsigned int format) 59842542f5fSchristos{ 59942542f5fSchristos struct sna *sna = to_sna_from_drawable(draw); 60042542f5fSchristos DRI2Buffer2Ptr buffer; 60142542f5fSchristos struct sna_dri2_private *private; 60242542f5fSchristos PixmapPtr pixmap; 60342542f5fSchristos struct kgem_bo *bo; 60463ef14f0Smrg unsigned bpp = format ?: draw->bitsPerPixel; 60563ef14f0Smrg unsigned flags = CREATE_EXACT; 60642542f5fSchristos uint32_t size; 60742542f5fSchristos 60813496ba1Ssnj DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n", 60942542f5fSchristos __FUNCTION__, 61042542f5fSchristos get_drawable_pixmap(draw)->drawable.serialNumber, 61113496ba1Ssnj attachment, format, draw->width, draw->height, 61213496ba1Ssnj draw->type != DRAWABLE_PIXMAP)); 61342542f5fSchristos 61442542f5fSchristos pixmap = NULL; 61542542f5fSchristos size = (uint32_t)draw->height << 16 | draw->width; 61642542f5fSchristos switch (attachment) { 61742542f5fSchristos case DRI2BufferFrontLeft: 61863ef14f0Smrg sna->needs_dri_flush = true; 61963ef14f0Smrg 62042542f5fSchristos pixmap = get_drawable_pixmap(draw); 62142542f5fSchristos buffer = NULL; 62242542f5fSchristos if (draw->type != DRAWABLE_PIXMAP) 62342542f5fSchristos buffer = dri2_window_get_front((WindowPtr)draw); 62442542f5fSchristos if (buffer == NULL) 62563ef14f0Smrg buffer = (DRI2Buffer2Ptr)sna_pixmap_get_buffer(pixmap); 62642542f5fSchristos if (buffer) { 62742542f5fSchristos private = get_private(buffer); 62842542f5fSchristos 62963ef14f0Smrg DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d, active_scanout=%d\n", 63042542f5fSchristos __FUNCTION__, 63142542f5fSchristos draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0, 63242542f5fSchristos draw->width, draw->height, 63342542f5fSchristos pixmap->drawable.serialNumber, 63413496ba1Ssnj private->pixmap->drawable.serialNumber, 63542542f5fSchristos pixmap->drawable.width, 63642542f5fSchristos pixmap->drawable.height, 63763ef14f0Smrg private->bo->handle, buffer->name, 63863ef14f0Smrg private->bo->active_scanout)); 63942542f5fSchristos 64063ef14f0Smrg assert(buffer->attachment == DRI2BufferFrontLeft); 64142542f5fSchristos assert(private->pixmap == pixmap); 64242542f5fSchristos assert(sna_pixmap(pixmap)->flush); 64342542f5fSchristos assert(sna_pixmap(pixmap)->pinned & PIN_DRI2); 64442542f5fSchristos assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name); 64563ef14f0Smrg assert(private->bo->pitch == buffer->pitch); 64663ef14f0Smrg assert(private->bo->active_scanout); 64742542f5fSchristos 64842542f5fSchristos private->refcnt++; 64942542f5fSchristos return buffer; 65042542f5fSchristos } 65142542f5fSchristos 65242542f5fSchristos bo = sna_pixmap_set_dri(sna, pixmap); 65342542f5fSchristos if (bo == NULL) 65442542f5fSchristos return NULL; 65542542f5fSchristos 65642542f5fSchristos assert(sna_pixmap(pixmap) != NULL); 65742542f5fSchristos 65842542f5fSchristos bo = ref(bo); 65942542f5fSchristos if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB)) 66042542f5fSchristos flags |= CREATE_SCANOUT; 66142542f5fSchristos DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n", 66242542f5fSchristos __FUNCTION__, 66342542f5fSchristos pixmap->drawable.width, pixmap->drawable.height, 66442542f5fSchristos pixmap, pixmap->refcnt, flags & CREATE_SCANOUT)); 66542542f5fSchristos size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width; 66663ef14f0Smrg bpp = pixmap->drawable.bitsPerPixel; 66742542f5fSchristos break; 66842542f5fSchristos 66942542f5fSchristos case DRI2BufferBackLeft: 67042542f5fSchristos if (draw->type != DRAWABLE_PIXMAP) { 67142542f5fSchristos if (dri2_window_get_front((WindowPtr)draw)) 67242542f5fSchristos flags |= CREATE_SCANOUT; 67342542f5fSchristos if (draw->width == sna->front->drawable.width && 67442542f5fSchristos draw->height == sna->front->drawable.height && 67563ef14f0Smrg draw->bitsPerPixel == bpp && 67642542f5fSchristos (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0) 67742542f5fSchristos flags |= CREATE_SCANOUT; 67842542f5fSchristos } 67942542f5fSchristos case DRI2BufferBackRight: 68042542f5fSchristos case DRI2BufferFrontRight: 68142542f5fSchristos case DRI2BufferFakeFrontLeft: 68242542f5fSchristos case DRI2BufferFakeFrontRight: 68342542f5fSchristos DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n", 68442542f5fSchristos __FUNCTION__, 68542542f5fSchristos draw->width, draw->height, 68642542f5fSchristos flags & CREATE_SCANOUT)); 68742542f5fSchristos 68842542f5fSchristos bo = kgem_create_2d(&sna->kgem, 68942542f5fSchristos draw->width, 69042542f5fSchristos draw->height, 69163ef14f0Smrg bpp, 69242542f5fSchristos color_tiling(sna, draw), 69342542f5fSchristos flags); 69442542f5fSchristos break; 69542542f5fSchristos 69642542f5fSchristos case DRI2BufferStencil: 69742542f5fSchristos /* 69842542f5fSchristos * The stencil buffer has quirky pitch requirements. From Vol 69942542f5fSchristos * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 70042542f5fSchristos * Pitch": 70142542f5fSchristos * The pitch must be set to 2x the value computed based on 70242542f5fSchristos * width, as the stencil buffer is stored with two rows 70342542f5fSchristos * interleaved. 70442542f5fSchristos * To accomplish this, we resort to the nasty hack of doubling 70542542f5fSchristos * the drm region's cpp and halving its height. 70642542f5fSchristos * 70742542f5fSchristos * If we neglect to double the pitch, then 70842542f5fSchristos * drm_intel_gem_bo_map_gtt() maps the memory incorrectly. 70942542f5fSchristos * 71042542f5fSchristos * The alignment for W-tiling is quite different to the 71142542f5fSchristos * nominal no-tiling case, so we have to account for 71242542f5fSchristos * the tiled access pattern explicitly. 71342542f5fSchristos * 71442542f5fSchristos * The stencil buffer is W tiled. However, we request from 71542542f5fSchristos * the kernel a non-tiled buffer because the kernel does 71642542f5fSchristos * not understand W tiling and the GTT is incapable of 71742542f5fSchristos * W fencing. 71842542f5fSchristos */ 71942542f5fSchristos bpp *= 2; 72042542f5fSchristos bo = kgem_create_2d(&sna->kgem, 72142542f5fSchristos ALIGN(draw->width, 64), 72242542f5fSchristos ALIGN((draw->height + 1) / 2, 64), 72342542f5fSchristos bpp, I915_TILING_NONE, flags); 72442542f5fSchristos break; 72542542f5fSchristos 72642542f5fSchristos case DRI2BufferDepth: 72742542f5fSchristos case DRI2BufferDepthStencil: 72842542f5fSchristos case DRI2BufferHiz: 72942542f5fSchristos case DRI2BufferAccum: 73042542f5fSchristos bo = kgem_create_2d(&sna->kgem, 73142542f5fSchristos draw->width, draw->height, bpp, 73242542f5fSchristos other_tiling(sna, draw), 73342542f5fSchristos flags); 73442542f5fSchristos break; 73542542f5fSchristos 73642542f5fSchristos default: 73742542f5fSchristos return NULL; 73842542f5fSchristos } 73942542f5fSchristos if (bo == NULL) 74042542f5fSchristos return NULL; 74142542f5fSchristos 74242542f5fSchristos buffer = calloc(1, sizeof *buffer + sizeof *private); 74342542f5fSchristos if (buffer == NULL) 74442542f5fSchristos goto err; 74542542f5fSchristos 74642542f5fSchristos private = get_private(buffer); 74742542f5fSchristos buffer->attachment = attachment; 74842542f5fSchristos buffer->pitch = bo->pitch; 74942542f5fSchristos buffer->cpp = bpp / 8; 75042542f5fSchristos buffer->driverPrivate = private; 75142542f5fSchristos buffer->format = format; 75242542f5fSchristos buffer->flags = 0; 75342542f5fSchristos buffer->name = kgem_bo_flink(&sna->kgem, bo); 75442542f5fSchristos private->refcnt = 1; 75542542f5fSchristos private->bo = bo; 75642542f5fSchristos private->pixmap = pixmap; 75742542f5fSchristos private->size = size; 75842542f5fSchristos 75942542f5fSchristos if (buffer->name == 0) 76042542f5fSchristos goto err; 76142542f5fSchristos 76242542f5fSchristos if (pixmap) { 76342542f5fSchristos struct sna_pixmap *priv; 76442542f5fSchristos 76542542f5fSchristos assert(attachment == DRI2BufferFrontLeft); 76642542f5fSchristos assert(sna_pixmap_get_buffer(pixmap) == NULL); 76742542f5fSchristos 76842542f5fSchristos sna_pixmap_set_buffer(pixmap, buffer); 76942542f5fSchristos assert(sna_pixmap_get_buffer(pixmap) == buffer); 77042542f5fSchristos pixmap->refcnt++; 77142542f5fSchristos 77242542f5fSchristos priv = sna_pixmap(pixmap); 77363ef14f0Smrg assert(priv->flush == false || priv->pinned & PIN_DRI3); 77442542f5fSchristos assert((priv->pinned & PIN_DRI2) == 0); 77542542f5fSchristos 77642542f5fSchristos /* Don't allow this named buffer to be replaced */ 77742542f5fSchristos priv->pinned |= PIN_DRI2; 77842542f5fSchristos 77942542f5fSchristos /* We need to submit any modifications to and reads from this 78042542f5fSchristos * buffer before we send any reply to the Client. 78142542f5fSchristos * 78242542f5fSchristos * As we don't track which Client, we flush for all. 78342542f5fSchristos */ 78442542f5fSchristos DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, priv->gpu_bo->handle)); 78542542f5fSchristos priv->gpu_bo->flush = true; 78642542f5fSchristos if (priv->gpu_bo->exec) 78742542f5fSchristos sna->kgem.flush = 1; 78842542f5fSchristos 78963ef14f0Smrg priv->flush |= FLUSH_READ; 79042542f5fSchristos if (draw->type == DRAWABLE_PIXMAP) { 79142542f5fSchristos /* DRI2 renders directly into GLXPixmaps, treat as hostile */ 79242542f5fSchristos kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 79342542f5fSchristos sna_damage_all(&priv->gpu_damage, pixmap); 79442542f5fSchristos priv->clear = false; 79542542f5fSchristos priv->cpu = false; 79663ef14f0Smrg priv->flush |= FLUSH_WRITE; 79742542f5fSchristos } 79842542f5fSchristos 79963ef14f0Smrg sna_watch_flush(sna, 1); 80042542f5fSchristos } 80142542f5fSchristos 80242542f5fSchristos return buffer; 80342542f5fSchristos 80442542f5fSchristoserr: 80542542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 80642542f5fSchristos free(buffer); 80742542f5fSchristos return NULL; 80842542f5fSchristos} 80942542f5fSchristos 81063ef14f0Smrgstatic void 81163ef14f0Smrgsna_dri2_cache_bo(struct sna *sna, 81263ef14f0Smrg DrawablePtr draw, 81363ef14f0Smrg struct kgem_bo *bo, 81463ef14f0Smrg uint32_t name, 81563ef14f0Smrg uint32_t size, 81663ef14f0Smrg uint32_t flags) 81763ef14f0Smrg{ 81863ef14f0Smrg struct dri_bo *c; 81963ef14f0Smrg 82063ef14f0Smrg DBG(("%s(handle=%d, name=%d)\n", __FUNCTION__, bo->handle, name)); 82163ef14f0Smrg 82263ef14f0Smrg if (draw == NULL) { 82363ef14f0Smrg DBG(("%s: no draw, releasing handle=%d\n", 82463ef14f0Smrg __FUNCTION__, bo->handle)); 82563ef14f0Smrg goto err; 82663ef14f0Smrg } 82763ef14f0Smrg 82863ef14f0Smrg if (draw->type == DRAWABLE_PIXMAP) { 82963ef14f0Smrg DBG(("%s: not a window, releasing handle=%d\n", 83063ef14f0Smrg __FUNCTION__, bo->handle)); 83163ef14f0Smrg goto err; 83263ef14f0Smrg } 83363ef14f0Smrg 83463ef14f0Smrg if (bo->refcnt > 1 + bo->active_scanout) { 83563ef14f0Smrg DBG(("%s: multiple references [%d], releasing handle\n", 83663ef14f0Smrg __FUNCTION__, bo->refcnt, bo->handle)); 83763ef14f0Smrg goto err; 83863ef14f0Smrg } 83963ef14f0Smrg 84063ef14f0Smrg if ((draw->height << 16 | draw->width) != size) { 84163ef14f0Smrg DBG(("%s: wrong size [%dx%d], releasing handle\n", 84263ef14f0Smrg __FUNCTION__, 84363ef14f0Smrg size & 0xffff, size >> 16, 84463ef14f0Smrg bo->handle)); 84563ef14f0Smrg goto err; 84663ef14f0Smrg } 84763ef14f0Smrg 84863ef14f0Smrg if (bo->scanout && front_pitch(draw) != bo->pitch) { 84963ef14f0Smrg DBG(("%s: scanout with pitch change [%d != %d], releasing handle\n", 85063ef14f0Smrg __FUNCTION__, bo->pitch, front_pitch(draw), bo->handle)); 85163ef14f0Smrg goto err; 85263ef14f0Smrg } 85363ef14f0Smrg 85463ef14f0Smrg c = malloc(sizeof(*c)); 85563ef14f0Smrg if (!c) 85663ef14f0Smrg goto err; 85763ef14f0Smrg 85863ef14f0Smrg DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, bo->handle, name, flags, bo->active_scanout)); 85963ef14f0Smrg 86063ef14f0Smrg c->bo = bo; 86163ef14f0Smrg c->name = name; 86263ef14f0Smrg c->flags = flags; 86363ef14f0Smrg list_add(&c->link, &dri2_window((WindowPtr)draw)->cache); 86463ef14f0Smrg return; 86563ef14f0Smrg 86663ef14f0Smrgerr: 86763ef14f0Smrg kgem_bo_destroy(&sna->kgem, bo); 86863ef14f0Smrg} 86963ef14f0Smrg 87063ef14f0Smrgstatic void _sna_dri2_destroy_buffer(struct sna *sna, 87163ef14f0Smrg DrawablePtr draw, 87263ef14f0Smrg DRI2Buffer2Ptr buffer) 87342542f5fSchristos{ 87442542f5fSchristos struct sna_dri2_private *private = get_private(buffer); 87542542f5fSchristos 87642542f5fSchristos if (buffer == NULL) 87742542f5fSchristos return; 87842542f5fSchristos 87963ef14f0Smrg DBG(("%s: %p [handle=%d] -- refcnt=%d, draw=%ld, pixmap=%ld, proxy?=%d\n", 88042542f5fSchristos __FUNCTION__, buffer, private->bo->handle, private->refcnt, 88163ef14f0Smrg draw ? draw->id : 0, 88263ef14f0Smrg private->pixmap ? private->pixmap->drawable.serialNumber : 0, 88363ef14f0Smrg private->proxy != NULL)); 88442542f5fSchristos assert(private->refcnt > 0); 88542542f5fSchristos if (--private->refcnt) 88642542f5fSchristos return; 88742542f5fSchristos 88842542f5fSchristos assert(private->bo); 88942542f5fSchristos 89042542f5fSchristos if (private->proxy) { 89142542f5fSchristos DBG(("%s: destroying proxy\n", __FUNCTION__)); 89263ef14f0Smrg assert(private->bo->active_scanout > 0); 89363ef14f0Smrg private->bo->active_scanout--; 89463ef14f0Smrg 89563ef14f0Smrg _sna_dri2_destroy_buffer(sna, draw, private->proxy); 89642542f5fSchristos private->pixmap = NULL; 89742542f5fSchristos } 89842542f5fSchristos 89942542f5fSchristos if (private->pixmap) { 90042542f5fSchristos PixmapPtr pixmap = private->pixmap; 90142542f5fSchristos struct sna_pixmap *priv = sna_pixmap(pixmap); 90242542f5fSchristos 90342542f5fSchristos assert(sna_pixmap_get_buffer(pixmap) == buffer); 90442542f5fSchristos assert(priv->gpu_bo == private->bo); 90542542f5fSchristos assert(priv->gpu_bo->flush); 90642542f5fSchristos assert(priv->pinned & PIN_DRI2); 90742542f5fSchristos assert(priv->flush); 90842542f5fSchristos 90963ef14f0Smrg DBG(("%s: removing active_scanout=%d from pixmap handle=%d\n", 91063ef14f0Smrg __FUNCTION__, priv->gpu_bo->active_scanout, priv->gpu_bo->handle)); 91163ef14f0Smrg assert(priv->gpu_bo->active_scanout > 0); 91263ef14f0Smrg priv->gpu_bo->active_scanout--; 91363ef14f0Smrg 91442542f5fSchristos /* Undo the DRI markings on this pixmap */ 91542542f5fSchristos DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n", 91642542f5fSchristos __FUNCTION__, 91742542f5fSchristos pixmap->drawable.serialNumber, 91842542f5fSchristos pixmap == sna->front)); 91942542f5fSchristos 92042542f5fSchristos list_del(&priv->flush_list); 92142542f5fSchristos 92242542f5fSchristos DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle)); 92342542f5fSchristos priv->pinned &= ~PIN_DRI2; 92442542f5fSchristos 92563ef14f0Smrg if ((priv->pinned & PIN_DRI3) == 0) { 92663ef14f0Smrg priv->gpu_bo->flush = false; 92763ef14f0Smrg priv->flush = false; 92863ef14f0Smrg } 92963ef14f0Smrg sna_watch_flush(sna, -1); 93042542f5fSchristos 93142542f5fSchristos sna_pixmap_set_buffer(pixmap, NULL); 93242542f5fSchristos pixmap->drawable.pScreen->DestroyPixmap(pixmap); 93342542f5fSchristos } 93442542f5fSchristos 93563ef14f0Smrg sna_dri2_cache_bo(sna, draw, 93663ef14f0Smrg private->bo, 93763ef14f0Smrg buffer->name, 93863ef14f0Smrg private->size, 93963ef14f0Smrg buffer->flags); 94042542f5fSchristos free(buffer); 94142542f5fSchristos} 94242542f5fSchristos 94342542f5fSchristosstatic void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer) 94442542f5fSchristos{ 94563ef14f0Smrg _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), draw, buffer); 94642542f5fSchristos} 94742542f5fSchristos 94842542f5fSchristosstatic DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer) 94942542f5fSchristos{ 95063ef14f0Smrg assert(get_private(buffer)->refcnt > 0); 95142542f5fSchristos get_private(buffer)->refcnt++; 95242542f5fSchristos return buffer; 95342542f5fSchristos} 95442542f5fSchristos 95542542f5fSchristosstatic inline void damage(PixmapPtr pixmap, struct sna_pixmap *priv, RegionPtr region) 95642542f5fSchristos{ 95742542f5fSchristos assert(priv->gpu_bo); 95842542f5fSchristos if (DAMAGE_IS_ALL(priv->gpu_damage)) 95942542f5fSchristos goto done; 96042542f5fSchristos 96142542f5fSchristos if (region == NULL) { 96242542f5fSchristosdamage_all: 96342542f5fSchristos priv->gpu_damage = _sna_damage_all(priv->gpu_damage, 96442542f5fSchristos pixmap->drawable.width, 96542542f5fSchristos pixmap->drawable.height); 96642542f5fSchristos sna_damage_destroy(&priv->cpu_damage); 96742542f5fSchristos list_del(&priv->flush_list); 96842542f5fSchristos } else { 96942542f5fSchristos sna_damage_subtract(&priv->cpu_damage, region); 97042542f5fSchristos if (priv->cpu_damage == NULL) 97142542f5fSchristos goto damage_all; 97242542f5fSchristos sna_damage_add(&priv->gpu_damage, region); 97342542f5fSchristos } 97442542f5fSchristosdone: 97542542f5fSchristos priv->cpu = false; 97642542f5fSchristos priv->clear = false; 97742542f5fSchristos} 97842542f5fSchristos 97942542f5fSchristosstatic void set_bo(PixmapPtr pixmap, struct kgem_bo *bo) 98042542f5fSchristos{ 98142542f5fSchristos struct sna *sna = to_sna_from_pixmap(pixmap); 98242542f5fSchristos struct sna_pixmap *priv = sna_pixmap(pixmap); 98342542f5fSchristos 98463ef14f0Smrg DBG(("%s: pixmap=%ld, handle=%d (old handle=%d)\n", 98563ef14f0Smrg __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, priv->gpu_bo->handle)); 98642542f5fSchristos 98742542f5fSchristos assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch); 98842542f5fSchristos assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo)); 98942542f5fSchristos assert(bo->proxy == NULL); 99042542f5fSchristos assert(priv->pinned & PIN_DRI2); 99142542f5fSchristos assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0); 99242542f5fSchristos assert(priv->flush); 99342542f5fSchristos 99463ef14f0Smrg if (APPLY_DAMAGE) { 99563ef14f0Smrg RegionRec region; 99663ef14f0Smrg 99763ef14f0Smrg /* Post damage on the new front buffer so that listeners, such 99863ef14f0Smrg * as DisplayLink know take a copy and shove it over the USB, 99963ef14f0Smrg * also for software cursors and the like. 100063ef14f0Smrg */ 100163ef14f0Smrg region.extents.x1 = region.extents.y1 = 0; 100263ef14f0Smrg region.extents.x2 = pixmap->drawable.width; 100363ef14f0Smrg region.extents.y2 = pixmap->drawable.height; 100463ef14f0Smrg region.data = NULL; 100563ef14f0Smrg 100663ef14f0Smrg /* 100763ef14f0Smrg * Eeek, beware the sw cursor copying to the old bo 100863ef14f0Smrg * causing recursion and mayhem. 100963ef14f0Smrg */ 101063ef14f0Smrg DBG(("%s: marking whole pixmap as damaged\n", __FUNCTION__)); 101163ef14f0Smrg sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE; 101263ef14f0Smrg DamageRegionAppend(&pixmap->drawable, ®ion); 101363ef14f0Smrg } 101442542f5fSchristos 101542542f5fSchristos damage(pixmap, priv, NULL); 101642542f5fSchristos 101742542f5fSchristos assert(bo->refcnt); 101863ef14f0Smrg if (priv->move_to_gpu) { 101963ef14f0Smrg DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__)); 102042542f5fSchristos priv->move_to_gpu(sna, priv, 0); 102163ef14f0Smrg } 102242542f5fSchristos if (priv->gpu_bo != bo) { 102342542f5fSchristos DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle)); 102442542f5fSchristos priv->gpu_bo->flush = false; 102542542f5fSchristos if (priv->cow) 102642542f5fSchristos sna_pixmap_undo_cow(sna, priv, 0); 102742542f5fSchristos if (priv->gpu_bo) { 102842542f5fSchristos sna_pixmap_unmap(pixmap, priv); 102942542f5fSchristos kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 103042542f5fSchristos } 103142542f5fSchristos DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle)); 103242542f5fSchristos bo->flush = true; 103342542f5fSchristos if (bo->exec) 103442542f5fSchristos sna->kgem.flush = 1; 103542542f5fSchristos priv->gpu_bo = ref(bo); 103642542f5fSchristos } 103742542f5fSchristos if (bo->domain != DOMAIN_GPU) 103842542f5fSchristos bo->domain = DOMAIN_NONE; 103942542f5fSchristos assert(bo->flush); 104042542f5fSchristos 104163ef14f0Smrg if (APPLY_DAMAGE) { 104263ef14f0Smrg sna->ignore_copy_area = false; 104363ef14f0Smrg DamageRegionProcessPending(&pixmap->drawable); 104463ef14f0Smrg } 104563ef14f0Smrg} 104663ef14f0Smrg 104763ef14f0Smrg#if defined(__GNUC__) 104863ef14f0Smrg#define popcount(x) __builtin_popcount(x) 104963ef14f0Smrg#else 105063ef14f0Smrgstatic int popcount(unsigned int x) 105163ef14f0Smrg{ 105263ef14f0Smrg int count = 0; 105363ef14f0Smrg 105463ef14f0Smrg while (x) { 105563ef14f0Smrg count += x&1; 105663ef14f0Smrg x >>= 1; 105763ef14f0Smrg } 105863ef14f0Smrg 105963ef14f0Smrg return count; 106042542f5fSchristos} 106163ef14f0Smrg#endif 106242542f5fSchristos 106342542f5fSchristosstatic void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync) 106442542f5fSchristos{ 106542542f5fSchristos struct drm_i915_gem_busy busy; 106642542f5fSchristos int mode; 106742542f5fSchristos 106842542f5fSchristos if (sna->kgem.gen < 060) 106942542f5fSchristos return; 107042542f5fSchristos 107142542f5fSchristos if (sync) { 107242542f5fSchristos DBG(("%s: sync, force %s ring\n", __FUNCTION__, 107342542f5fSchristos sna->kgem.gen >= 070 ? "BLT" : "RENDER")); 107442542f5fSchristos kgem_set_mode(&sna->kgem, 107542542f5fSchristos sna->kgem.gen >= 070 ? KGEM_BLT : KGEM_RENDER, 107642542f5fSchristos dst); 107742542f5fSchristos return; 107842542f5fSchristos } 107942542f5fSchristos 108042542f5fSchristos if (DBG_FORCE_COPY != -1) { 108142542f5fSchristos DBG(("%s: forcing %d\n", __FUNCTION__, DBG_FORCE_COPY)); 108242542f5fSchristos kgem_set_mode(&sna->kgem, DBG_FORCE_COPY, dst); 108342542f5fSchristos return; 108442542f5fSchristos } 108542542f5fSchristos 108642542f5fSchristos if (sna->kgem.mode != KGEM_NONE) { 108742542f5fSchristos DBG(("%s: busy, not switching\n", __FUNCTION__)); 108842542f5fSchristos return; 108942542f5fSchristos } 109042542f5fSchristos 109163ef14f0Smrg if (sna->render_state.gt < 2 && sna->kgem.has_semaphores) { 109263ef14f0Smrg DBG(("%s: small GT [%d], not forcing selection\n", 109363ef14f0Smrg __FUNCTION__, sna->render_state.gt)); 109463ef14f0Smrg return; 109563ef14f0Smrg } 109663ef14f0Smrg 109742542f5fSchristos VG_CLEAR(busy); 109842542f5fSchristos busy.handle = src->handle; 109942542f5fSchristos if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy)) 110042542f5fSchristos return; 110142542f5fSchristos 110242542f5fSchristos DBG(("%s: src handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy)); 110342542f5fSchristos if (busy.busy == 0) { 110442542f5fSchristos __kgem_bo_clear_busy(src); 110542542f5fSchristos 110642542f5fSchristos busy.handle = dst->handle; 110742542f5fSchristos if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy)) 110842542f5fSchristos return; 110942542f5fSchristos 111042542f5fSchristos DBG(("%s: dst handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy)); 111142542f5fSchristos if (busy.busy == 0) { 111242542f5fSchristos __kgem_bo_clear_busy(dst); 111342542f5fSchristos DBG(("%s: src/dst is idle, using defaults\n", __FUNCTION__)); 111442542f5fSchristos return; 111542542f5fSchristos } 111642542f5fSchristos } 111742542f5fSchristos 111842542f5fSchristos /* Sandybridge introduced a separate ring which it uses to 111942542f5fSchristos * perform blits. Switching rendering between rings incurs 112042542f5fSchristos * a stall as we wait upon the old ring to finish and 112142542f5fSchristos * flush its render cache before we can proceed on with 112242542f5fSchristos * the operation on the new ring. 112342542f5fSchristos * 112442542f5fSchristos * As this buffer, we presume, has just been written to by 112542542f5fSchristos * the DRI client using the RENDER ring, we want to perform 112642542f5fSchristos * our operation on the same ring, and ideally on the same 112742542f5fSchristos * ring as we will flip from (which should be the RENDER ring 112842542f5fSchristos * as well). 112942542f5fSchristos * 113042542f5fSchristos * The ultimate question is whether preserving the ring outweighs 113142542f5fSchristos * the cost of the query. 113242542f5fSchristos */ 113342542f5fSchristos mode = KGEM_RENDER; 113463ef14f0Smrg if ((busy.busy & 0xffff) == I915_EXEC_BLT) 113542542f5fSchristos mode = KGEM_BLT; 113663ef14f0Smrg kgem_bo_mark_busy(&sna->kgem, 113763ef14f0Smrg busy.handle == src->handle ? src : dst, 113863ef14f0Smrg mode); 113942542f5fSchristos _kgem_set_mode(&sna->kgem, mode); 114042542f5fSchristos} 114142542f5fSchristos 114242542f5fSchristosstatic bool is_front(int attachment) 114342542f5fSchristos{ 114442542f5fSchristos return attachment == DRI2BufferFrontLeft; 114542542f5fSchristos} 114642542f5fSchristos 114763ef14f0Smrg#define DRI2_SYNC 0x1 114863ef14f0Smrg#define DRI2_DAMAGE 0x2 114963ef14f0Smrg#define DRI2_BO 0x4 115042542f5fSchristosstatic struct kgem_bo * 115142542f5fSchristos__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region, 115242542f5fSchristos DRI2BufferPtr src, DRI2BufferPtr dst, 115363ef14f0Smrg unsigned flags) 115442542f5fSchristos{ 115542542f5fSchristos PixmapPtr pixmap = get_drawable_pixmap(draw); 115642542f5fSchristos DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable; 115742542f5fSchristos struct sna_dri2_private *src_priv = get_private(src); 115842542f5fSchristos struct sna_dri2_private *dst_priv = get_private(dst); 115942542f5fSchristos pixman_region16_t clip; 116042542f5fSchristos struct kgem_bo *bo = NULL; 116142542f5fSchristos struct kgem_bo *src_bo; 116242542f5fSchristos struct kgem_bo *dst_bo; 116342542f5fSchristos const BoxRec *boxes; 116442542f5fSchristos int16_t dx, dy, sx, sy; 116563ef14f0Smrg unsigned hint; 116642542f5fSchristos int n; 116742542f5fSchristos 116842542f5fSchristos /* To hide a stale DRI2Buffer, one may choose to substitute 116942542f5fSchristos * pixmap->gpu_bo instead of dst/src->bo, however you then run 117042542f5fSchristos * the risk of copying around invalid data. So either you may not 117142542f5fSchristos * see the results of the copy, or you may see the wrong pixels. 117242542f5fSchristos * Either way you eventually lose. 117342542f5fSchristos * 117442542f5fSchristos * We also have to be careful in case that the stale buffers are 117542542f5fSchristos * now attached to invalid (non-DRI) pixmaps. 117642542f5fSchristos */ 117742542f5fSchristos 117842542f5fSchristos assert(is_front(dst->attachment) || is_front(src->attachment)); 117942542f5fSchristos assert(dst->attachment != src->attachment); 118042542f5fSchristos 118142542f5fSchristos clip.extents.x1 = draw->x; 118242542f5fSchristos clip.extents.y1 = draw->y; 118342542f5fSchristos clip.extents.x2 = draw->x + draw->width; 118442542f5fSchristos clip.extents.y2 = draw->y + draw->height; 118542542f5fSchristos clip.data = NULL; 118642542f5fSchristos 118742542f5fSchristos if (region) { 118842542f5fSchristos pixman_region_translate(region, draw->x, draw->y); 118942542f5fSchristos pixman_region_intersect(&clip, &clip, region); 119042542f5fSchristos region = &clip; 119142542f5fSchristos } 119242542f5fSchristos 119342542f5fSchristos if (clip.extents.x1 >= clip.extents.x2 || 119442542f5fSchristos clip.extents.y1 >= clip.extents.y2) { 119542542f5fSchristos DBG(("%s: all clipped\n", __FUNCTION__)); 119642542f5fSchristos return NULL; 119742542f5fSchristos } 119842542f5fSchristos 119942542f5fSchristos sx = sy = dx = dy = 0; 120042542f5fSchristos if (is_front(dst->attachment)) { 120142542f5fSchristos sx = -draw->x; 120242542f5fSchristos sy = -draw->y; 120342542f5fSchristos } else { 120442542f5fSchristos dx = -draw->x; 120542542f5fSchristos dy = -draw->y; 120642542f5fSchristos } 120742542f5fSchristos if (draw->type == DRAWABLE_WINDOW) { 120842542f5fSchristos WindowPtr win = (WindowPtr)draw; 120942542f5fSchristos int16_t tx, ty; 121042542f5fSchristos 121142542f5fSchristos if (is_clipped(&win->clipList, draw)) { 121242542f5fSchristos DBG(("%s: draw=(%d, %d), delta=(%d, %d), draw=(%d, %d),(%d, %d), clip.extents=(%d, %d), (%d, %d)\n", 121342542f5fSchristos __FUNCTION__, draw->x, draw->y, 121442542f5fSchristos get_drawable_dx(draw), get_drawable_dy(draw), 121542542f5fSchristos clip.extents.x1, clip.extents.y1, 121642542f5fSchristos clip.extents.x2, clip.extents.y2, 121742542f5fSchristos win->clipList.extents.x1, win->clipList.extents.y1, 121842542f5fSchristos win->clipList.extents.x2, win->clipList.extents.y2)); 121942542f5fSchristos 122042542f5fSchristos assert(region == NULL || region == &clip); 122142542f5fSchristos pixman_region_intersect(&clip, &win->clipList, &clip); 122242542f5fSchristos if (!pixman_region_not_empty(&clip)) { 122342542f5fSchristos DBG(("%s: all clipped\n", __FUNCTION__)); 122442542f5fSchristos return NULL; 122542542f5fSchristos } 122642542f5fSchristos 122742542f5fSchristos region = &clip; 122842542f5fSchristos } 122942542f5fSchristos 123042542f5fSchristos if (get_drawable_deltas(draw, pixmap, &tx, &ty)) { 123142542f5fSchristos if (is_front(dst->attachment)) { 123242542f5fSchristos pixman_region_translate(region ?: &clip, tx, ty); 123342542f5fSchristos sx -= tx; 123442542f5fSchristos sy -= ty; 123542542f5fSchristos } else { 123642542f5fSchristos sx += tx; 123742542f5fSchristos sy += ty; 123842542f5fSchristos } 123942542f5fSchristos } 124042542f5fSchristos } else 124163ef14f0Smrg flags &= ~DRI2_SYNC; 124242542f5fSchristos 124363ef14f0Smrg scratch.pScreen = draw->pScreen; 124442542f5fSchristos scratch.x = scratch.y = 0; 124542542f5fSchristos scratch.width = scratch.height = 0; 124642542f5fSchristos scratch.depth = draw->depth; 124742542f5fSchristos scratch.bitsPerPixel = draw->bitsPerPixel; 124842542f5fSchristos 124942542f5fSchristos src_bo = src_priv->bo; 125042542f5fSchristos assert(src_bo->refcnt); 125163ef14f0Smrg kgem_bo_unclean(&sna->kgem, src_bo); 125242542f5fSchristos if (is_front(src->attachment)) { 125342542f5fSchristos struct sna_pixmap *priv; 125442542f5fSchristos 125542542f5fSchristos priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 125642542f5fSchristos if (priv) 125742542f5fSchristos src_bo = priv->gpu_bo; 125842542f5fSchristos DBG(("%s: updated FrontLeft src_bo from handle=%d to handle=%d\n", 125942542f5fSchristos __FUNCTION__, src_priv->bo->handle, src_bo->handle)); 126042542f5fSchristos assert(src_bo->refcnt); 126142542f5fSchristos } else { 126242542f5fSchristos RegionRec source; 126342542f5fSchristos 126442542f5fSchristos scratch.width = src_priv->size & 0xffff; 126542542f5fSchristos scratch.height = src_priv->size >> 16; 126642542f5fSchristos src_draw = &scratch; 126742542f5fSchristos 126863ef14f0Smrg DBG(("%s: source size %dx%d, region size %dx%d, src offset %dx%d\n", 126942542f5fSchristos __FUNCTION__, 127042542f5fSchristos scratch.width, scratch.height, 127142542f5fSchristos clip.extents.x2 - clip.extents.x1, 127263ef14f0Smrg clip.extents.y2 - clip.extents.y1, 127363ef14f0Smrg -sx, -sy)); 127442542f5fSchristos 127542542f5fSchristos source.extents.x1 = -sx; 127642542f5fSchristos source.extents.y1 = -sy; 127742542f5fSchristos source.extents.x2 = source.extents.x1 + scratch.width; 127842542f5fSchristos source.extents.y2 = source.extents.y1 + scratch.height; 127942542f5fSchristos source.data = NULL; 128042542f5fSchristos 128142542f5fSchristos assert(region == NULL || region == &clip); 128242542f5fSchristos pixman_region_intersect(&clip, &clip, &source); 128342542f5fSchristos 128463ef14f0Smrg if (!pixman_region_not_empty(&clip)) { 128563ef14f0Smrg DBG(("%s: region doesn't overlap pixmap\n", __FUNCTION__)); 128663ef14f0Smrg return NULL; 128763ef14f0Smrg } 128842542f5fSchristos } 128942542f5fSchristos 129042542f5fSchristos dst_bo = dst_priv->bo; 129142542f5fSchristos assert(dst_bo->refcnt); 129242542f5fSchristos if (is_front(dst->attachment)) { 129342542f5fSchristos struct sna_pixmap *priv; 129413496ba1Ssnj struct list shadow; 129513496ba1Ssnj 129613496ba1Ssnj /* Preserve the CRTC shadow overrides */ 129713496ba1Ssnj sna_shadow_steal_crtcs(sna, &shadow); 129842542f5fSchristos 129963ef14f0Smrg hint = MOVE_WRITE | __MOVE_FORCE; 130042542f5fSchristos if (clip.data) 130163ef14f0Smrg hint |= MOVE_READ; 130242542f5fSchristos 130342542f5fSchristos assert(region == NULL || region == &clip); 130463ef14f0Smrg priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, hint); 130542542f5fSchristos if (priv) { 130663ef14f0Smrg damage(pixmap, priv, region ?: &clip); 130742542f5fSchristos dst_bo = priv->gpu_bo; 130842542f5fSchristos } 130942542f5fSchristos DBG(("%s: updated FrontLeft dst_bo from handle=%d to handle=%d\n", 131042542f5fSchristos __FUNCTION__, dst_priv->bo->handle, dst_bo->handle)); 131142542f5fSchristos assert(dst_bo->refcnt); 131213496ba1Ssnj 131313496ba1Ssnj sna_shadow_unsteal_crtcs(sna, &shadow); 131442542f5fSchristos } else { 131542542f5fSchristos RegionRec target; 131642542f5fSchristos 131742542f5fSchristos scratch.width = dst_priv->size & 0xffff; 131842542f5fSchristos scratch.height = dst_priv->size >> 16; 131942542f5fSchristos dst_draw = &scratch; 132042542f5fSchristos 132142542f5fSchristos DBG(("%s: target size %dx%d, region size %dx%d\n", 132242542f5fSchristos __FUNCTION__, 132342542f5fSchristos scratch.width, scratch.height, 132442542f5fSchristos clip.extents.x2 - clip.extents.x1, 132542542f5fSchristos clip.extents.y2 - clip.extents.y1)); 132642542f5fSchristos 132742542f5fSchristos target.extents.x1 = -dx; 132842542f5fSchristos target.extents.y1 = -dy; 132942542f5fSchristos target.extents.x2 = target.extents.x1 + scratch.width; 133042542f5fSchristos target.extents.y2 = target.extents.y1 + scratch.height; 133142542f5fSchristos target.data = NULL; 133242542f5fSchristos 133342542f5fSchristos assert(region == NULL || region == &clip); 133442542f5fSchristos pixman_region_intersect(&clip, &clip, &target); 133542542f5fSchristos 133663ef14f0Smrg flags &= ~DRI2_SYNC; 133742542f5fSchristos } 133842542f5fSchristos 133942542f5fSchristos if (!wedged(sna)) { 134042542f5fSchristos xf86CrtcPtr crtc; 134142542f5fSchristos 134242542f5fSchristos crtc = NULL; 134363ef14f0Smrg if (flags & DRI2_SYNC && sna_pixmap_is_scanout(sna, pixmap)) 134442542f5fSchristos crtc = sna_covering_crtc(sna, &clip.extents, NULL); 134542542f5fSchristos sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL); 134642542f5fSchristos 134763ef14f0Smrg if (crtc == NULL || 134863ef14f0Smrg !sna_wait_for_scanline(sna, pixmap, crtc, &clip.extents)) 134963ef14f0Smrg flags &= ~DRI2_SYNC; 135042542f5fSchristos } 135142542f5fSchristos 135242542f5fSchristos if (region) { 135342542f5fSchristos boxes = region_rects(region); 135442542f5fSchristos n = region_num_rects(region); 135542542f5fSchristos assert(n); 135642542f5fSchristos } else { 135742542f5fSchristos region = &clip; 135842542f5fSchristos boxes = &clip.extents; 135942542f5fSchristos n = 1; 136042542f5fSchristos } 136163ef14f0Smrg if (APPLY_DAMAGE || flags & DRI2_DAMAGE) { 136263ef14f0Smrg DBG(("%s: marking region as damaged\n", __FUNCTION__)); 136363ef14f0Smrg sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE; 136463ef14f0Smrg DamageRegionAppend(&pixmap->drawable, region); 136563ef14f0Smrg } 136642542f5fSchristos 136713496ba1Ssnj DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n", 136813496ba1Ssnj __FUNCTION__, 136913496ba1Ssnj boxes[0].x1, boxes[0].y1, 137013496ba1Ssnj boxes[0].x2, boxes[0].y2, 137113496ba1Ssnj n, sx, sy, dx, dy)); 137213496ba1Ssnj 137363ef14f0Smrg hint = COPY_LAST | COPY_DRI; 137463ef14f0Smrg if (flags & DRI2_SYNC) 137563ef14f0Smrg hint |= COPY_SYNC; 137613496ba1Ssnj if (!sna->render.copy_boxes(sna, GXcopy, 137713496ba1Ssnj src_draw, src_bo, sx, sy, 137813496ba1Ssnj dst_draw, dst_bo, dx, dy, 137963ef14f0Smrg boxes, n, hint)) 138013496ba1Ssnj memcpy_copy_boxes(sna, GXcopy, 138113496ba1Ssnj src_draw, src_bo, sx, sy, 138213496ba1Ssnj dst_draw, dst_bo, dx, dy, 138363ef14f0Smrg boxes, n, hint); 138463ef14f0Smrg 138563ef14f0Smrg sna->needs_dri_flush = true; 138663ef14f0Smrg if (flags & (DRI2_SYNC | DRI2_BO)) { /* STAT! */ 138763ef14f0Smrg struct kgem_request *rq = RQ(dst_bo->rq); 138863ef14f0Smrg if (rq && rq != (void *)&sna->kgem) { 138963ef14f0Smrg if (rq->bo == NULL) 139063ef14f0Smrg kgem_submit(&sna->kgem); 139163ef14f0Smrg if (rq->bo) { /* Becareful in case the gpu is wedged */ 139263ef14f0Smrg bo = ref(rq->bo); 139363ef14f0Smrg DBG(("%s: recording sync fence handle=%d\n", 139463ef14f0Smrg __FUNCTION__, bo->handle)); 139563ef14f0Smrg } 139642542f5fSchristos } 139742542f5fSchristos } 139842542f5fSchristos 139963ef14f0Smrg if (APPLY_DAMAGE || flags & DRI2_DAMAGE) { 140063ef14f0Smrg sna->ignore_copy_area = false; 140163ef14f0Smrg DamageRegionProcessPending(&pixmap->drawable); 140263ef14f0Smrg } 140342542f5fSchristos 140442542f5fSchristos if (clip.data) 140542542f5fSchristos pixman_region_fini(&clip); 140642542f5fSchristos 140742542f5fSchristos return bo; 140842542f5fSchristos} 140942542f5fSchristos 141042542f5fSchristosstatic void 141142542f5fSchristossna_dri2_copy_region(DrawablePtr draw, 141242542f5fSchristos RegionPtr region, 141342542f5fSchristos DRI2BufferPtr dst, 141442542f5fSchristos DRI2BufferPtr src) 141542542f5fSchristos{ 141642542f5fSchristos PixmapPtr pixmap = get_drawable_pixmap(draw); 141742542f5fSchristos struct sna *sna = to_sna_from_pixmap(pixmap); 141842542f5fSchristos 141942542f5fSchristos DBG(("%s: pixmap=%ld, src=%u (refs=%d/%d, flush=%d, attach=%d) , dst=%u (refs=%d/%d, flush=%d, attach=%d)\n", 142042542f5fSchristos __FUNCTION__, 142142542f5fSchristos pixmap->drawable.serialNumber, 142242542f5fSchristos get_private(src)->bo->handle, 142342542f5fSchristos get_private(src)->refcnt, 142442542f5fSchristos get_private(src)->bo->refcnt, 142542542f5fSchristos get_private(src)->bo->flush, 142642542f5fSchristos src->attachment, 142742542f5fSchristos get_private(dst)->bo->handle, 142842542f5fSchristos get_private(dst)->refcnt, 142942542f5fSchristos get_private(dst)->bo->refcnt, 143042542f5fSchristos get_private(dst)->bo->flush, 143142542f5fSchristos dst->attachment)); 143242542f5fSchristos 143342542f5fSchristos assert(src != dst); 143442542f5fSchristos 143542542f5fSchristos assert(get_private(src)->refcnt); 143642542f5fSchristos assert(get_private(dst)->refcnt); 143742542f5fSchristos 143863ef14f0Smrg assert(get_private(src)->bo != get_private(dst)->bo); 143963ef14f0Smrg 144042542f5fSchristos assert(get_private(src)->bo->refcnt); 144142542f5fSchristos assert(get_private(dst)->bo->refcnt); 144242542f5fSchristos 144342542f5fSchristos DBG(("%s: region (%d, %d), (%d, %d) x %d\n", 144442542f5fSchristos __FUNCTION__, 144542542f5fSchristos region->extents.x1, region->extents.y1, 144642542f5fSchristos region->extents.x2, region->extents.y2, 144742542f5fSchristos region_num_rects(region))); 144842542f5fSchristos 144963ef14f0Smrg __sna_dri2_copy_region(sna, draw, region, src, dst, DRI2_DAMAGE); 145042542f5fSchristos} 145142542f5fSchristos 145242542f5fSchristosinline static uint32_t pipe_select(int pipe) 145342542f5fSchristos{ 145442542f5fSchristos /* The third pipe was introduced with IvyBridge long after 145542542f5fSchristos * multiple pipe support was added to the kernel, hence 145642542f5fSchristos * we can safely ignore the capability check - if we have more 145742542f5fSchristos * than two pipes, we can assume that they are fully supported. 145842542f5fSchristos */ 145963ef14f0Smrg assert(pipe < _DRM_VBLANK_HIGH_CRTC_MASK); 146042542f5fSchristos if (pipe > 1) 146142542f5fSchristos return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 146242542f5fSchristos else if (pipe > 0) 146342542f5fSchristos return DRM_VBLANK_SECONDARY; 146442542f5fSchristos else 146542542f5fSchristos return 0; 146642542f5fSchristos} 146742542f5fSchristos 146863ef14f0Smrgstatic inline bool sna_next_vblank(struct sna_dri2_event *info) 146942542f5fSchristos{ 147063ef14f0Smrg union drm_wait_vblank vbl; 147142542f5fSchristos 147263ef14f0Smrg DBG(("%s(pipe=%d, waiting until next vblank)\n", 147363ef14f0Smrg __FUNCTION__, info->pipe)); 147463ef14f0Smrg assert(info->pipe != -1); 147563ef14f0Smrg 147663ef14f0Smrg VG_CLEAR(vbl); 147763ef14f0Smrg vbl.request.type = 147863ef14f0Smrg DRM_VBLANK_RELATIVE | 147963ef14f0Smrg DRM_VBLANK_EVENT | 148063ef14f0Smrg pipe_select(info->pipe); 148163ef14f0Smrg vbl.request.sequence = 1; 148263ef14f0Smrg vbl.request.signal = (uintptr_t)info; 148363ef14f0Smrg 148463ef14f0Smrg assert(!info->queued); 148563ef14f0Smrg if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl)) 148663ef14f0Smrg return false; 148763ef14f0Smrg 148863ef14f0Smrg info->queued = true; 148963ef14f0Smrg return true; 149063ef14f0Smrg} 149163ef14f0Smrg 149263ef14f0Smrgstatic inline bool sna_wait_vblank(struct sna_dri2_event *info, 149363ef14f0Smrg unsigned seq) 149463ef14f0Smrg{ 149563ef14f0Smrg union drm_wait_vblank vbl; 149663ef14f0Smrg 149763ef14f0Smrg DBG(("%s(pipe=%d, waiting until vblank %u)\n", 149863ef14f0Smrg __FUNCTION__, info->pipe, seq)); 149963ef14f0Smrg assert(info->pipe != -1); 150063ef14f0Smrg 150163ef14f0Smrg VG_CLEAR(vbl); 150263ef14f0Smrg vbl.request.type = 150363ef14f0Smrg DRM_VBLANK_ABSOLUTE | 150463ef14f0Smrg DRM_VBLANK_EVENT | 150563ef14f0Smrg pipe_select(info->pipe); 150663ef14f0Smrg vbl.request.sequence = seq; 150763ef14f0Smrg vbl.request.signal = (uintptr_t)info; 150863ef14f0Smrg 150963ef14f0Smrg assert(!info->queued); 151063ef14f0Smrg if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl)) 151163ef14f0Smrg return false; 151263ef14f0Smrg 151363ef14f0Smrg info->queued = true; 151463ef14f0Smrg return true; 151542542f5fSchristos} 151642542f5fSchristos 151742542f5fSchristos#if DRI2INFOREC_VERSION >= 4 151842542f5fSchristos 151942542f5fSchristosstatic void dri2_window_attach(WindowPtr win, struct dri2_window *priv) 152042542f5fSchristos{ 152142542f5fSchristos assert(win->drawable.type == DRAWABLE_WINDOW); 152242542f5fSchristos assert(dri2_window(win) == NULL); 152342542f5fSchristos ((void **)__get_private(win, sna_window_key))[1] = priv; 152442542f5fSchristos assert(dri2_window(win) == priv); 152542542f5fSchristos} 152642542f5fSchristos 152742542f5fSchristosstatic uint64_t 152842542f5fSchristosdraw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc) 152942542f5fSchristos{ 153042542f5fSchristos struct dri2_window *priv; 153142542f5fSchristos 153263ef14f0Smrg assert(draw); 153342542f5fSchristos if (draw->type != DRAWABLE_WINDOW) 153442542f5fSchristos return msc; 153542542f5fSchristos 153642542f5fSchristos priv = dri2_window((WindowPtr)draw); 153742542f5fSchristos if (priv == NULL) { 153842542f5fSchristos priv = malloc(sizeof(*priv)); 153942542f5fSchristos if (priv != NULL) { 154042542f5fSchristos priv->front = NULL; 154142542f5fSchristos priv->crtc = crtc; 154242542f5fSchristos priv->msc_delta = 0; 154342542f5fSchristos priv->chain = NULL; 154463ef14f0Smrg priv->cache_size = 0; 154563ef14f0Smrg list_init(&priv->cache); 154642542f5fSchristos dri2_window_attach((WindowPtr)draw, priv); 154742542f5fSchristos } 154842542f5fSchristos } else { 154942542f5fSchristos if (priv->crtc != crtc) { 155042542f5fSchristos const struct ust_msc *last = sna_crtc_last_swap(priv->crtc); 155142542f5fSchristos const struct ust_msc *this = sna_crtc_last_swap(crtc); 155242542f5fSchristos DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n", 155342542f5fSchristos __FUNCTION__, 155463ef14f0Smrg sna_crtc_pipe(priv->crtc), (long long)last->msc, 155563ef14f0Smrg sna_crtc_pipe(crtc), (long long)this->msc, 155642542f5fSchristos (long long)(priv->msc_delta + this->msc - last->msc))); 155742542f5fSchristos priv->msc_delta += this->msc - last->msc; 155842542f5fSchristos priv->crtc = crtc; 155942542f5fSchristos } 156042542f5fSchristos msc -= priv->msc_delta; 156142542f5fSchristos } 156242542f5fSchristos return msc; 156342542f5fSchristos} 156442542f5fSchristos 156542542f5fSchristosstatic uint32_t 156642542f5fSchristosdraw_target_seq(DrawablePtr draw, uint64_t msc) 156742542f5fSchristos{ 156842542f5fSchristos struct dri2_window *priv = dri2_window((WindowPtr)draw); 156942542f5fSchristos if (priv == NULL) 157042542f5fSchristos return msc; 157142542f5fSchristos DBG(("%s: converting target_msc=%llu to seq %u\n", 157242542f5fSchristos __FUNCTION__, (long long)msc, (unsigned)(msc + priv->msc_delta))); 157342542f5fSchristos return msc + priv->msc_delta; 157442542f5fSchristos} 157542542f5fSchristos 157642542f5fSchristosstatic xf86CrtcPtr 157742542f5fSchristossna_dri2_get_crtc(DrawablePtr draw) 157842542f5fSchristos{ 157942542f5fSchristos if (draw->type == DRAWABLE_PIXMAP) 158042542f5fSchristos return NULL; 158142542f5fSchristos 158242542f5fSchristos /* Make sure the CRTC is valid and this is the real front buffer */ 158313496ba1Ssnj return sna_covering_crtc(to_sna_from_drawable(draw), 158413496ba1Ssnj &((WindowPtr)draw)->clipList.extents, 158513496ba1Ssnj NULL); 158642542f5fSchristos} 158742542f5fSchristos 158863ef14f0Smrgstatic void frame_swap_complete(struct sna_dri2_event *frame, int type) 158942542f5fSchristos{ 159063ef14f0Smrg const struct ust_msc *swap; 159142542f5fSchristos 159263ef14f0Smrg assert(frame->signal); 159363ef14f0Smrg frame->signal = false; 159442542f5fSchristos 159563ef14f0Smrg if (frame->client == NULL) { 159663ef14f0Smrg DBG(("%s: client already gone\n", __FUNCTION__)); 159742542f5fSchristos return; 159842542f5fSchristos } 159942542f5fSchristos 160063ef14f0Smrg assert(frame->draw); 160163ef14f0Smrg 160263ef14f0Smrg swap = sna_crtc_last_swap(frame->crtc); 160363ef14f0Smrg DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n", 160463ef14f0Smrg __FUNCTION__, type, (long)frame->draw->id, frame->pipe, 160563ef14f0Smrg (long long)swap->msc, 160663ef14f0Smrg (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc), 160763ef14f0Smrg swap->tv_sec, swap->tv_usec)); 160863ef14f0Smrg 160963ef14f0Smrg DRI2SwapComplete(frame->client, frame->draw, 161063ef14f0Smrg draw_current_msc(frame->draw, frame->crtc, swap->msc), 161163ef14f0Smrg swap->tv_sec, swap->tv_usec, 161263ef14f0Smrg type, frame->event_complete, frame->event_data); 161342542f5fSchristos} 161442542f5fSchristos 161563ef14f0Smrgstatic void fake_swap_complete(struct sna *sna, ClientPtr client, 161663ef14f0Smrg DrawablePtr draw, xf86CrtcPtr crtc, 161763ef14f0Smrg int type, DRI2SwapEventPtr func, void *data) 161842542f5fSchristos{ 161963ef14f0Smrg const struct ust_msc *swap; 162042542f5fSchristos 162163ef14f0Smrg assert(draw); 162242542f5fSchristos 162363ef14f0Smrg if (crtc == NULL) 162463ef14f0Smrg crtc = sna_primary_crtc(sna); 162542542f5fSchristos 162663ef14f0Smrg swap = sna_crtc_last_swap(crtc); 162763ef14f0Smrg DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n", 162863ef14f0Smrg __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1, 162963ef14f0Smrg (long long)swap->msc, 163063ef14f0Smrg (long long)draw_current_msc(draw, crtc, swap->msc), 163163ef14f0Smrg swap->tv_sec, swap->tv_usec)); 163242542f5fSchristos 163363ef14f0Smrg DRI2SwapComplete(client, draw, 163463ef14f0Smrg draw_current_msc(draw, crtc, swap->msc), 163563ef14f0Smrg swap->tv_sec, swap->tv_usec, 163663ef14f0Smrg type, func, data); 163763ef14f0Smrg} 163842542f5fSchristos 163963ef14f0Smrgstatic void 164063ef14f0Smrgsna_dri2_remove_event(struct sna_dri2_event *info) 164163ef14f0Smrg{ 164263ef14f0Smrg WindowPtr win = (WindowPtr)info->draw; 164363ef14f0Smrg struct dri2_window *priv; 164442542f5fSchristos 164563ef14f0Smrg assert(win->drawable.type == DRAWABLE_WINDOW); 164663ef14f0Smrg DBG(("%s: remove[%p] from window %ld, active? %d\n", 164763ef14f0Smrg __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL)); 164863ef14f0Smrg assert(!info->signal); 164963ef14f0Smrg 165063ef14f0Smrg priv = dri2_window(win); 165163ef14f0Smrg assert(priv); 165263ef14f0Smrg assert(priv->chain != NULL); 165363ef14f0Smrg assert(info->chained); 165463ef14f0Smrg info->chained = false; 165563ef14f0Smrg 165663ef14f0Smrg if (priv->chain != info) { 165763ef14f0Smrg struct sna_dri2_event *chain = priv->chain; 165863ef14f0Smrg while (chain->chain != info) { 165963ef14f0Smrg assert(chain->chained); 166063ef14f0Smrg chain = chain->chain; 166163ef14f0Smrg } 166263ef14f0Smrg assert(chain != info); 166363ef14f0Smrg assert(info->chain != chain); 166463ef14f0Smrg chain->chain = info->chain; 166563ef14f0Smrg return; 166663ef14f0Smrg } 166763ef14f0Smrg 166863ef14f0Smrg priv->chain = info->chain; 166963ef14f0Smrg if (priv->chain == NULL) { 167063ef14f0Smrg struct dri_bo *c, *tmp; 167163ef14f0Smrg 167263ef14f0Smrg c = list_entry(priv->cache.next->next, struct dri_bo, link); 167363ef14f0Smrg list_for_each_entry_safe_from(c, tmp, &priv->cache, link) { 167463ef14f0Smrg list_del(&c->link); 167563ef14f0Smrg 167663ef14f0Smrg DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0)); 167763ef14f0Smrg assert(c->bo); 167863ef14f0Smrg kgem_bo_destroy(&info->sna->kgem, c->bo); 167963ef14f0Smrg free(c); 168063ef14f0Smrg } 168142542f5fSchristos } 168263ef14f0Smrg} 168363ef14f0Smrg 168463ef14f0Smrgstatic void 168563ef14f0Smrgsna_dri2_event_free(struct sna_dri2_event *info) 168663ef14f0Smrg{ 168763ef14f0Smrg DBG(("%s(draw?=%d)\n", __FUNCTION__, info->draw != NULL)); 168863ef14f0Smrg assert(!info->queued); 168963ef14f0Smrg assert(!info->signal); 169063ef14f0Smrg assert(info->pending.bo == NULL); 169163ef14f0Smrg 169263ef14f0Smrg if (info->sna->dri2.flip_pending == info) 169363ef14f0Smrg info->sna->dri2.flip_pending = NULL; 169463ef14f0Smrg assert(info->sna->dri2.flip_pending != info); 169563ef14f0Smrg if (info->chained) 169663ef14f0Smrg sna_dri2_remove_event(info); 169763ef14f0Smrg 169863ef14f0Smrg assert((info->front == NULL && info->back == NULL) || info->front != info->back); 169963ef14f0Smrg _sna_dri2_destroy_buffer(info->sna, info->draw, info->front); 170063ef14f0Smrg _sna_dri2_destroy_buffer(info->sna, info->draw, info->back); 170142542f5fSchristos 170242542f5fSchristos if (info->bo) { 170342542f5fSchristos DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle)); 170413496ba1Ssnj kgem_bo_destroy(&info->sna->kgem, info->bo); 170542542f5fSchristos } 170642542f5fSchristos 170742542f5fSchristos _list_del(&info->link); 170842542f5fSchristos free(info); 170942542f5fSchristos} 171042542f5fSchristos 171142542f5fSchristosstatic void 171242542f5fSchristossna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data) 171342542f5fSchristos{ 171442542f5fSchristos NewClientInfoRec *clientinfo = data; 171542542f5fSchristos ClientPtr client = clientinfo->client; 171642542f5fSchristos struct sna_client *priv = sna_client(client); 171742542f5fSchristos struct sna *sna = closure; 171842542f5fSchristos 171942542f5fSchristos if (priv->events.next == NULL) 172042542f5fSchristos return; 172142542f5fSchristos 172242542f5fSchristos if (client->clientState != ClientStateGone) 172342542f5fSchristos return; 172442542f5fSchristos 172542542f5fSchristos DBG(("%s(active?=%d)\n", __FUNCTION__, 172642542f5fSchristos !list_is_empty(&priv->events))); 172742542f5fSchristos 172842542f5fSchristos while (!list_is_empty(&priv->events)) { 172942542f5fSchristos struct sna_dri2_event *event; 173042542f5fSchristos 173142542f5fSchristos event = list_first_entry(&priv->events, struct sna_dri2_event, link); 173242542f5fSchristos assert(event->client == client); 173363ef14f0Smrg list_del(&event->link); 173463ef14f0Smrg event->signal = false; 173542542f5fSchristos 173663ef14f0Smrg if (event->pending.bo) { 173763ef14f0Smrg assert(event->pending.bo->active_scanout > 0); 173863ef14f0Smrg event->pending.bo->active_scanout--; 173963ef14f0Smrg 174063ef14f0Smrg kgem_bo_destroy(&sna->kgem, event->pending.bo); 174163ef14f0Smrg event->pending.bo = NULL; 174263ef14f0Smrg } 174363ef14f0Smrg 174463ef14f0Smrg if (event->chained) 174563ef14f0Smrg sna_dri2_remove_event(event); 174663ef14f0Smrg 174763ef14f0Smrg event->client = NULL; 174863ef14f0Smrg event->draw = NULL; 174963ef14f0Smrg event->keepalive = 1; 175063ef14f0Smrg assert(!event->signal); 175163ef14f0Smrg 175263ef14f0Smrg if (!event->queued) 175313496ba1Ssnj sna_dri2_event_free(event); 175442542f5fSchristos } 175542542f5fSchristos 175642542f5fSchristos if (--sna->dri2.client_count == 0) 175742542f5fSchristos DeleteCallback(&ClientStateCallback, sna_dri2_client_gone, sna); 175842542f5fSchristos} 175942542f5fSchristos 176042542f5fSchristosstatic bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, ClientPtr client) 176142542f5fSchristos{ 176242542f5fSchristos struct sna_client *priv = sna_client(client); 176342542f5fSchristos 176442542f5fSchristos if (priv->events.next == NULL) { 176542542f5fSchristos if (sna->dri2.client_count++ == 0 && 176642542f5fSchristos !AddCallback(&ClientStateCallback, sna_dri2_client_gone, sna)) 176742542f5fSchristos return false; 176842542f5fSchristos 176942542f5fSchristos list_init(&priv->events); 177042542f5fSchristos } 177142542f5fSchristos 177242542f5fSchristos list_add(&info->link, &priv->events); 177342542f5fSchristos info->client = client; 177442542f5fSchristos return true; 177542542f5fSchristos} 177642542f5fSchristos 177742542f5fSchristosstatic struct sna_dri2_event * 177863ef14f0Smrgsna_dri2_add_event(struct sna *sna, 177963ef14f0Smrg DrawablePtr draw, 178063ef14f0Smrg ClientPtr client, 178163ef14f0Smrg xf86CrtcPtr crtc) 178242542f5fSchristos{ 178342542f5fSchristos struct dri2_window *priv; 178442542f5fSchristos struct sna_dri2_event *info, *chain; 178542542f5fSchristos 178663ef14f0Smrg assert(draw != NULL); 178742542f5fSchristos assert(draw->type == DRAWABLE_WINDOW); 178842542f5fSchristos DBG(("%s: adding event to window %ld)\n", 178942542f5fSchristos __FUNCTION__, (long)draw->id)); 179042542f5fSchristos 179142542f5fSchristos priv = dri2_window((WindowPtr)draw); 179242542f5fSchristos if (priv == NULL) 179342542f5fSchristos return NULL; 179442542f5fSchristos 179542542f5fSchristos info = calloc(1, sizeof(struct sna_dri2_event)); 179642542f5fSchristos if (info == NULL) 179742542f5fSchristos return NULL; 179842542f5fSchristos 179913496ba1Ssnj info->sna = sna; 180042542f5fSchristos info->draw = draw; 180163ef14f0Smrg info->crtc = crtc; 180263ef14f0Smrg info->pipe = sna_crtc_pipe(crtc); 180363ef14f0Smrg info->keepalive = 1; 180442542f5fSchristos 180542542f5fSchristos if (!add_event_to_client(info, sna, client)) { 180642542f5fSchristos free(info); 180742542f5fSchristos return NULL; 180842542f5fSchristos } 180942542f5fSchristos 181042542f5fSchristos assert(priv->chain != info); 181163ef14f0Smrg info->chained = true; 181242542f5fSchristos 181342542f5fSchristos if (priv->chain == NULL) { 181442542f5fSchristos priv->chain = info; 181542542f5fSchristos return info; 181642542f5fSchristos } 181742542f5fSchristos 181842542f5fSchristos chain = priv->chain; 181942542f5fSchristos while (chain->chain != NULL) 182042542f5fSchristos chain = chain->chain; 182142542f5fSchristos 182242542f5fSchristos assert(chain != info); 182342542f5fSchristos chain->chain = info; 182442542f5fSchristos return info; 182542542f5fSchristos} 182642542f5fSchristos 182763ef14f0Smrgstatic void decouple_window(WindowPtr win, 182863ef14f0Smrg struct dri2_window *priv, 182963ef14f0Smrg struct sna *sna, 183063ef14f0Smrg bool signal) 183113496ba1Ssnj{ 183213496ba1Ssnj if (priv->front) { 183363ef14f0Smrg DBG(("%s: decouple private front\n", __FUNCTION__)); 183413496ba1Ssnj assert(priv->crtc); 183513496ba1Ssnj sna_shadow_unset_crtc(sna, priv->crtc); 183613496ba1Ssnj 183763ef14f0Smrg _sna_dri2_destroy_buffer(sna, NULL, priv->front); 183863ef14f0Smrg priv->front = NULL; 183942542f5fSchristos } 184042542f5fSchristos 184142542f5fSchristos if (priv->chain) { 184242542f5fSchristos struct sna_dri2_event *info, *chain; 184342542f5fSchristos 184442542f5fSchristos DBG(("%s: freeing chain\n", __FUNCTION__)); 184542542f5fSchristos 184642542f5fSchristos chain = priv->chain; 184742542f5fSchristos while ((info = chain)) { 184863ef14f0Smrg DBG(("%s: freeing event, pending signal? %d, pending swap? handle=%d\n", 184963ef14f0Smrg __FUNCTION__, info->signal, 185063ef14f0Smrg info->pending.bo ? info->pending.bo->handle : 0)); 185163ef14f0Smrg assert(info->draw == &win->drawable); 185263ef14f0Smrg 185363ef14f0Smrg if (info->pending.bo) { 185463ef14f0Smrg if (signal) { 185563ef14f0Smrg bool was_signalling = info->signal; 185663ef14f0Smrg info->signal = true; 185763ef14f0Smrg frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE); 185863ef14f0Smrg info->signal = was_signalling; 185963ef14f0Smrg } 186063ef14f0Smrg assert(info->pending.bo->active_scanout > 0); 186163ef14f0Smrg info->pending.bo->active_scanout--; 186263ef14f0Smrg 186363ef14f0Smrg kgem_bo_destroy(&sna->kgem, info->pending.bo); 186463ef14f0Smrg info->pending.bo = NULL; 186563ef14f0Smrg } 186663ef14f0Smrg 186763ef14f0Smrg if (info->signal && signal) 186863ef14f0Smrg frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE); 186963ef14f0Smrg info->signal = false; 187042542f5fSchristos info->draw = NULL; 187163ef14f0Smrg info->keepalive = 1; 187263ef14f0Smrg assert(!info->signal); 187313496ba1Ssnj list_del(&info->link); 187442542f5fSchristos 187542542f5fSchristos chain = info->chain; 187642542f5fSchristos info->chain = NULL; 187763ef14f0Smrg info->chained = false; 187842542f5fSchristos 187942542f5fSchristos if (!info->queued) 188013496ba1Ssnj sna_dri2_event_free(info); 188142542f5fSchristos } 188263ef14f0Smrg 188363ef14f0Smrg priv->chain = NULL; 188463ef14f0Smrg } 188563ef14f0Smrg} 188663ef14f0Smrg 188763ef14f0Smrgvoid sna_dri2_decouple_window(WindowPtr win) 188863ef14f0Smrg{ 188963ef14f0Smrg struct dri2_window *priv; 189063ef14f0Smrg 189163ef14f0Smrg priv = dri2_window(win); 189263ef14f0Smrg if (priv == NULL) 189363ef14f0Smrg return; 189463ef14f0Smrg 189563ef14f0Smrg DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 189663ef14f0Smrg decouple_window(win, priv, to_sna_from_drawable(&win->drawable), true); 189763ef14f0Smrg} 189863ef14f0Smrg 189963ef14f0Smrgvoid sna_dri2_destroy_window(WindowPtr win) 190063ef14f0Smrg{ 190163ef14f0Smrg struct dri2_window *priv; 190263ef14f0Smrg struct sna *sna; 190363ef14f0Smrg 190463ef14f0Smrg priv = dri2_window(win); 190563ef14f0Smrg if (priv == NULL) 190663ef14f0Smrg return; 190763ef14f0Smrg 190863ef14f0Smrg DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 190963ef14f0Smrg sna = to_sna_from_drawable(&win->drawable); 191063ef14f0Smrg decouple_window(win, priv, sna, false); 191163ef14f0Smrg 191263ef14f0Smrg while (!list_is_empty(&priv->cache)) { 191363ef14f0Smrg struct dri_bo *c; 191463ef14f0Smrg 191563ef14f0Smrg c = list_first_entry(&priv->cache, struct dri_bo, link); 191663ef14f0Smrg list_del(&c->link); 191763ef14f0Smrg 191863ef14f0Smrg DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0)); 191963ef14f0Smrg assert(c->bo); 192063ef14f0Smrg kgem_bo_destroy(&sna->kgem, c->bo); 192163ef14f0Smrg free(c); 192242542f5fSchristos } 192342542f5fSchristos 192442542f5fSchristos free(priv); 192542542f5fSchristos} 192642542f5fSchristos 192742542f5fSchristosstatic void 192813496ba1Ssnjsna_dri2_flip_handler(struct drm_event_vblank *event, void *data) 192942542f5fSchristos{ 193042542f5fSchristos DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence)); 193113496ba1Ssnj sna_dri2_flip_event(data); 193242542f5fSchristos} 193342542f5fSchristos 193442542f5fSchristosstatic bool 193513496ba1Ssnjsna_dri2_flip(struct sna_dri2_event *info) 193642542f5fSchristos{ 193742542f5fSchristos struct kgem_bo *bo = get_private(info->back)->bo; 193842542f5fSchristos struct kgem_bo *tmp_bo; 193963ef14f0Smrg uint32_t tmp_name, tmp_flags; 194013496ba1Ssnj int tmp_pitch; 194142542f5fSchristos 194242542f5fSchristos DBG(("%s(type=%d)\n", __FUNCTION__, info->type)); 194342542f5fSchristos 194413496ba1Ssnj assert(sna_pixmap_get_buffer(info->sna->front) == info->front); 194542542f5fSchristos assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo)); 194663ef14f0Smrg assert(get_private(info->front)->size == get_private(info->back)->size); 194742542f5fSchristos assert(bo->refcnt); 194842542f5fSchristos 194963ef14f0Smrg if (info->sna->mode.flip_active) { 195063ef14f0Smrg DBG(("%s: %d flips still active, aborting\n", 195163ef14f0Smrg __FUNCTION__, info->sna->mode.flip_active)); 195263ef14f0Smrg return false; 195363ef14f0Smrg } 195463ef14f0Smrg 195563ef14f0Smrg assert(!info->queued); 195613496ba1Ssnj if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, 195742542f5fSchristos info->type == FLIP_ASYNC ? NULL : info)) 195842542f5fSchristos return false; 195942542f5fSchristos 196063ef14f0Smrg DBG(("%s: queued flip=%p\n", __FUNCTION__, info->type == FLIP_ASYNC ? NULL : info)); 196163ef14f0Smrg assert(info->signal || info->type != FLIP_THROTTLE); 196263ef14f0Smrg 196313496ba1Ssnj assert(info->sna->dri2.flip_pending == NULL || 196413496ba1Ssnj info->sna->dri2.flip_pending == info); 196542542f5fSchristos if (info->type != FLIP_ASYNC) 196613496ba1Ssnj info->sna->dri2.flip_pending = info; 196742542f5fSchristos 196842542f5fSchristos DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n", 196942542f5fSchristos __FUNCTION__, bo->handle, 197042542f5fSchristos get_private(info->front)->bo->handle, info->front->name, 197142542f5fSchristos get_private(info->back)->bo->handle, info->back->name)); 197242542f5fSchristos 197342542f5fSchristos tmp_bo = get_private(info->front)->bo; 197442542f5fSchristos tmp_name = info->front->name; 197513496ba1Ssnj tmp_pitch = info->front->pitch; 197663ef14f0Smrg tmp_flags = info->front->flags; 197763ef14f0Smrg 197863ef14f0Smrg assert(tmp_bo->active_scanout > 0); 197963ef14f0Smrg tmp_bo->active_scanout--; 198042542f5fSchristos 198113496ba1Ssnj set_bo(info->sna->front, bo); 198242542f5fSchristos 198363ef14f0Smrg info->front->flags = info->back->flags; 198442542f5fSchristos info->front->name = info->back->name; 198513496ba1Ssnj info->front->pitch = info->back->pitch; 198642542f5fSchristos get_private(info->front)->bo = bo; 198763ef14f0Smrg bo->active_scanout++; 198863ef14f0Smrg assert(bo->active_scanout <= bo->refcnt); 198942542f5fSchristos 199063ef14f0Smrg info->back->flags = tmp_flags; 199142542f5fSchristos info->back->name = tmp_name; 199213496ba1Ssnj info->back->pitch = tmp_pitch; 199342542f5fSchristos get_private(info->back)->bo = tmp_bo; 199413496ba1Ssnj mark_stale(info->back); 199542542f5fSchristos 199642542f5fSchristos assert(get_private(info->front)->bo->refcnt); 199742542f5fSchristos assert(get_private(info->back)->bo->refcnt); 199842542f5fSchristos assert(get_private(info->front)->bo != get_private(info->back)->bo); 199942542f5fSchristos 200063ef14f0Smrg info->keepalive = KEEPALIVE; 200142542f5fSchristos info->queued = true; 200242542f5fSchristos return true; 200342542f5fSchristos} 200442542f5fSchristos 200542542f5fSchristosstatic bool 200642542f5fSchristoscan_flip(struct sna * sna, 200742542f5fSchristos DrawablePtr draw, 200842542f5fSchristos DRI2BufferPtr front, 200942542f5fSchristos DRI2BufferPtr back, 201042542f5fSchristos xf86CrtcPtr crtc) 201142542f5fSchristos{ 201242542f5fSchristos WindowPtr win = (WindowPtr)draw; 201342542f5fSchristos PixmapPtr pixmap; 201442542f5fSchristos 201542542f5fSchristos assert((sna->flags & SNA_NO_WAIT) == 0); 201642542f5fSchristos 201742542f5fSchristos if (!DBG_CAN_FLIP) 201842542f5fSchristos return false; 201942542f5fSchristos 202042542f5fSchristos if (draw->type == DRAWABLE_PIXMAP) 202142542f5fSchristos return false; 202242542f5fSchristos 202342542f5fSchristos if (!sna->mode.front_active) { 202442542f5fSchristos DBG(("%s: no, active CRTC\n", __FUNCTION__)); 202542542f5fSchristos return false; 202642542f5fSchristos } 202742542f5fSchristos 202842542f5fSchristos assert(sna->scrn->vtSema); 202963ef14f0Smrg assert(!sna->mode.hidden); 203042542f5fSchristos 203142542f5fSchristos if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) { 203242542f5fSchristos DBG(("%s: no, pageflips disabled\n", __FUNCTION__)); 203342542f5fSchristos return false; 203442542f5fSchristos } 203542542f5fSchristos 203663ef14f0Smrg if (front->cpp != back->cpp) { 203742542f5fSchristos DBG(("%s: no, format mismatch, front = %d, back = %d\n", 203863ef14f0Smrg __FUNCTION__, front->cpp, back->cpp)); 203942542f5fSchristos return false; 204042542f5fSchristos } 204142542f5fSchristos 204242542f5fSchristos if (sna->mode.shadow_active) { 204342542f5fSchristos DBG(("%s: no, shadow enabled\n", __FUNCTION__)); 204442542f5fSchristos return false; 204542542f5fSchristos } 204642542f5fSchristos 204742542f5fSchristos if (!sna_crtc_is_on(crtc)) { 204863ef14f0Smrg DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc))); 204942542f5fSchristos return false; 205042542f5fSchristos } 205142542f5fSchristos 205242542f5fSchristos pixmap = get_window_pixmap(win); 205342542f5fSchristos if (pixmap != sna->front) { 205442542f5fSchristos DBG(("%s: no, window (pixmap=%ld) is not attached to the front buffer (pixmap=%ld)\n", 205542542f5fSchristos __FUNCTION__, pixmap->drawable.serialNumber, sna->front->drawable.serialNumber)); 205642542f5fSchristos return false; 205742542f5fSchristos } 205842542f5fSchristos 205942542f5fSchristos if (sna_pixmap_get_buffer(pixmap) != front) { 206042542f5fSchristos DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n", 206142542f5fSchristos __FUNCTION__, front->name, 206263ef14f0Smrg sna_pixmap_get_buffer(pixmap) ? sna_pixmap_get_buffer(pixmap)->name : 0, 206342542f5fSchristos pixmap->drawable.serialNumber)); 206442542f5fSchristos return false; 206542542f5fSchristos } 206642542f5fSchristos 206742542f5fSchristos assert(get_private(front)->pixmap == sna->front); 206842542f5fSchristos assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo); 206942542f5fSchristos 207042542f5fSchristos if (!get_private(back)->bo->scanout) { 207142542f5fSchristos DBG(("%s: no, DRI2 drawable was too small at time of creation)\n", 207242542f5fSchristos __FUNCTION__)); 207342542f5fSchristos return false; 207442542f5fSchristos } 207542542f5fSchristos 207642542f5fSchristos if (get_private(back)->size != get_private(front)->size) { 207742542f5fSchristos DBG(("%s: no, DRI2 drawable does not fit into scanout\n", 207842542f5fSchristos __FUNCTION__)); 207942542f5fSchristos return false; 208042542f5fSchristos } 208142542f5fSchristos 208242542f5fSchristos DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n", 208342542f5fSchristos __FUNCTION__, 208442542f5fSchristos win->drawable.width, win->drawable.height, 208542542f5fSchristos win->clipList.extents.x1, win->clipList.extents.y1, 208642542f5fSchristos win->clipList.extents.x2, win->clipList.extents.y2, 208742542f5fSchristos region_num_rects(&win->clipList))); 208842542f5fSchristos if (!RegionEqual(&win->clipList, &draw->pScreen->root->winSize)) { 208942542f5fSchristos DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n", 209042542f5fSchristos __FUNCTION__, 209142542f5fSchristos win->clipList.extents.x1, 209242542f5fSchristos win->clipList.extents.y1, 209342542f5fSchristos win->clipList.extents.x2, 209442542f5fSchristos win->clipList.extents.y2, 209542542f5fSchristos draw->pScreen->root->winSize.extents.x1, 209642542f5fSchristos draw->pScreen->root->winSize.extents.y1, 209742542f5fSchristos draw->pScreen->root->winSize.extents.x2, 209842542f5fSchristos draw->pScreen->root->winSize.extents.y2)); 209942542f5fSchristos return false; 210042542f5fSchristos } 210142542f5fSchristos 210242542f5fSchristos if (draw->x != 0 || draw->y != 0 || 210342542f5fSchristos#ifdef COMPOSITE 210442542f5fSchristos draw->x != pixmap->screen_x || 210542542f5fSchristos draw->y != pixmap->screen_y || 210642542f5fSchristos#endif 210742542f5fSchristos draw->width != pixmap->drawable.width || 210842542f5fSchristos draw->height != pixmap->drawable.height) { 210942542f5fSchristos DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n", 211042542f5fSchristos __FUNCTION__, 211142542f5fSchristos draw->width, draw->height, 211242542f5fSchristos pixmap->drawable.width, 211342542f5fSchristos pixmap->drawable.height)); 211442542f5fSchristos return false; 211542542f5fSchristos } 211642542f5fSchristos 211742542f5fSchristos /* prevent an implicit tiling mode change */ 211842542f5fSchristos if (get_private(back)->bo->tiling > I915_TILING_X) { 211942542f5fSchristos DBG(("%s -- no, tiling mismatch: front %d, back=%d, want-tiled?=%d\n", 212042542f5fSchristos __FUNCTION__, 212142542f5fSchristos get_private(front)->bo->tiling, 212242542f5fSchristos get_private(back)->bo->tiling, 212342542f5fSchristos !!(sna->flags & SNA_LINEAR_FB))); 212442542f5fSchristos return false; 212542542f5fSchristos } 212642542f5fSchristos 212742542f5fSchristos if (get_private(front)->bo->pitch != get_private(back)->bo->pitch) { 212842542f5fSchristos DBG(("%s -- no, pitch mismatch: front %d, back=%d\n", 212942542f5fSchristos __FUNCTION__, 213042542f5fSchristos get_private(front)->bo->pitch, 213142542f5fSchristos get_private(back)->bo->pitch)); 213242542f5fSchristos return false; 213342542f5fSchristos } 213442542f5fSchristos 213542542f5fSchristos if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) { 213642542f5fSchristos DBG(("%s -- no, pinned: front %x\n", 213742542f5fSchristos __FUNCTION__, sna_pixmap(pixmap)->pinned)); 213842542f5fSchristos return false; 213942542f5fSchristos } 214042542f5fSchristos 214142542f5fSchristos DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 214242542f5fSchristos return true; 214342542f5fSchristos} 214442542f5fSchristos 214542542f5fSchristosstatic bool 214613496ba1Ssnjcan_xchg(struct sna *sna, 214742542f5fSchristos DrawablePtr draw, 214842542f5fSchristos DRI2BufferPtr front, 214942542f5fSchristos DRI2BufferPtr back) 215042542f5fSchristos{ 215142542f5fSchristos WindowPtr win = (WindowPtr)draw; 215242542f5fSchristos PixmapPtr pixmap; 215342542f5fSchristos 215442542f5fSchristos if (!DBG_CAN_XCHG) 215542542f5fSchristos return false; 215642542f5fSchristos 215742542f5fSchristos if (draw->type == DRAWABLE_PIXMAP) 215842542f5fSchristos return false; 215942542f5fSchristos 216063ef14f0Smrg if (front->cpp != back->cpp) { 216142542f5fSchristos DBG(("%s: no, format mismatch, front = %d, back = %d\n", 216263ef14f0Smrg __FUNCTION__, front->cpp, back->cpp)); 216342542f5fSchristos return false; 216442542f5fSchristos } 216542542f5fSchristos 216642542f5fSchristos pixmap = get_window_pixmap(win); 216742542f5fSchristos if (get_private(front)->pixmap != pixmap) { 216842542f5fSchristos DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n", 216942542f5fSchristos __FUNCTION__, 217042542f5fSchristos get_private(front)->pixmap->drawable.serialNumber, 217142542f5fSchristos pixmap->drawable.serialNumber)); 217242542f5fSchristos return false; 217342542f5fSchristos } 217442542f5fSchristos 217542542f5fSchristos DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d, pixmap size=%dx%d\n", 217642542f5fSchristos __FUNCTION__, 217742542f5fSchristos win->drawable.width, win->drawable.height, 217842542f5fSchristos win->clipList.extents.x1, win->clipList.extents.y1, 217942542f5fSchristos win->clipList.extents.x2, win->clipList.extents.y2, 218042542f5fSchristos region_num_rects(&win->clipList), 218142542f5fSchristos pixmap->drawable.width, 218242542f5fSchristos pixmap->drawable.height)); 218342542f5fSchristos if (is_clipped(&win->clipList, &pixmap->drawable)) { 218442542f5fSchristos DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n", 218542542f5fSchristos __FUNCTION__, 218642542f5fSchristos draw->width, draw->height, 218742542f5fSchristos win->clipList.extents.x1, 218842542f5fSchristos win->clipList.extents.y1, 218942542f5fSchristos win->clipList.extents.x2, 219042542f5fSchristos win->clipList.extents.y2)); 219142542f5fSchristos return false; 219242542f5fSchristos } 219342542f5fSchristos 219463ef14f0Smrg DBG(("%s: back size=%x, front size=%x\n", 219563ef14f0Smrg __FUNCTION__, get_private(back)->size, get_private(front)->size)); 219642542f5fSchristos if (get_private(back)->size != get_private(front)->size) { 219742542f5fSchristos DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n", 219842542f5fSchristos __FUNCTION__, 219942542f5fSchristos get_private(back)->size & 0x7fff, (get_private(back)->size >> 16) & 0x7fff, 220042542f5fSchristos get_private(front)->size & 0x7fff, (get_private(front)->size >> 16) & 0x7fff)); 220142542f5fSchristos return false; 220242542f5fSchristos } 220342542f5fSchristos 220442542f5fSchristos if (pixmap == sna->front && !(sna->flags & SNA_TEAR_FREE) && sna->mode.front_active) { 220542542f5fSchristos DBG(("%s: no, front buffer, requires flipping\n", 220642542f5fSchristos __FUNCTION__)); 220742542f5fSchristos return false; 220842542f5fSchristos } 220942542f5fSchristos 221042542f5fSchristos if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) { 221142542f5fSchristos DBG(("%s: no, pinned: %x\n", 221242542f5fSchristos __FUNCTION__, sna_pixmap(pixmap)->pinned)); 221342542f5fSchristos return false; 221442542f5fSchristos } 221542542f5fSchristos 221642542f5fSchristos DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 221742542f5fSchristos return true; 221842542f5fSchristos} 221942542f5fSchristos 222042542f5fSchristosstatic bool 222142542f5fSchristosoverlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired) 222242542f5fSchristos{ 222342542f5fSchristos xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 222442542f5fSchristos int c; 222542542f5fSchristos 222642542f5fSchristos for (c = 0; c < sna->mode.num_real_crtc; c++) { 222742542f5fSchristos xf86CrtcPtr crtc = config->crtc[c]; 222842542f5fSchristos 222942542f5fSchristos if (crtc == desired) 223042542f5fSchristos continue; 223142542f5fSchristos 223242542f5fSchristos if (!crtc->enabled) 223342542f5fSchristos continue; 223442542f5fSchristos 223542542f5fSchristos if (desired->bounds.x1 < crtc->bounds.x2 && 223642542f5fSchristos desired->bounds.x2 > crtc->bounds.x1 && 223742542f5fSchristos desired->bounds.y1 < crtc->bounds.y2 && 223842542f5fSchristos desired->bounds.y2 > crtc->bounds.y1) 223942542f5fSchristos return true; 224042542f5fSchristos } 224142542f5fSchristos 224242542f5fSchristos return false; 224342542f5fSchristos} 224442542f5fSchristos 224542542f5fSchristosstatic bool 224642542f5fSchristoscan_xchg_crtc(struct sna *sna, 224742542f5fSchristos DrawablePtr draw, 224863ef14f0Smrg xf86CrtcPtr crtc, 224942542f5fSchristos DRI2BufferPtr front, 225063ef14f0Smrg DRI2BufferPtr back) 225142542f5fSchristos{ 225242542f5fSchristos WindowPtr win = (WindowPtr)draw; 225342542f5fSchristos PixmapPtr pixmap; 225442542f5fSchristos 225542542f5fSchristos if (!DBG_CAN_XCHG) 225642542f5fSchristos return false; 225742542f5fSchristos 225842542f5fSchristos if ((sna->flags & SNA_TEAR_FREE) == 0) { 225942542f5fSchristos DBG(("%s: no, requires TearFree\n", 226042542f5fSchristos __FUNCTION__)); 226142542f5fSchristos return false; 226242542f5fSchristos } 226342542f5fSchristos 226442542f5fSchristos if (draw->type == DRAWABLE_PIXMAP) 226542542f5fSchristos return false; 226642542f5fSchristos 226763ef14f0Smrg if (front->cpp != back->cpp) { 226842542f5fSchristos DBG(("%s: no, format mismatch, front = %d, back = %d\n", 226963ef14f0Smrg __FUNCTION__, front->cpp, back->cpp)); 227042542f5fSchristos return false; 227142542f5fSchristos } 227242542f5fSchristos 227342542f5fSchristos if (memcmp(&win->clipList.extents, &crtc->bounds, sizeof(crtc->bounds))) { 227442542f5fSchristos DBG(("%s: no, window [(%d, %d), (%d, %d)] does not cover CRTC [(%d, %d), (%d, %d)]\n", 227542542f5fSchristos __FUNCTION__, 227642542f5fSchristos win->clipList.extents.x1, win->clipList.extents.y1, 227742542f5fSchristos win->clipList.extents.x2, win->clipList.extents.y2, 227842542f5fSchristos crtc->bounds.x1, crtc->bounds.y1, 227942542f5fSchristos crtc->bounds.x2, crtc->bounds.y2)); 228042542f5fSchristos return false; 228142542f5fSchristos } 228242542f5fSchristos 228342542f5fSchristos if (sna_crtc_is_transformed(crtc)) { 228442542f5fSchristos DBG(("%s: no, CRTC is rotated\n", __FUNCTION__)); 228542542f5fSchristos return false; 228642542f5fSchristos } 228742542f5fSchristos 228842542f5fSchristos pixmap = get_window_pixmap(win); 228942542f5fSchristos if (pixmap != sna->front) { 229042542f5fSchristos DBG(("%s: no, not attached to front buffer\n", __FUNCTION__)); 229142542f5fSchristos return false; 229242542f5fSchristos } 229342542f5fSchristos 229442542f5fSchristos if (get_private(front)->pixmap != pixmap) { 229542542f5fSchristos DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n", 229642542f5fSchristos __FUNCTION__, 229742542f5fSchristos get_private(front)->pixmap->drawable.serialNumber, 229842542f5fSchristos pixmap->drawable.serialNumber)); 229942542f5fSchristos return false; 230042542f5fSchristos } 230142542f5fSchristos 230242542f5fSchristos DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n", 230342542f5fSchristos __FUNCTION__, 230442542f5fSchristos win->drawable.width, win->drawable.height, 230542542f5fSchristos win->clipList.extents.x1, win->clipList.extents.y1, 230642542f5fSchristos win->clipList.extents.x2, win->clipList.extents.y2, 230742542f5fSchristos region_num_rects(&win->clipList))); 230842542f5fSchristos if (is_clipped(&win->clipList, &win->drawable)) { 230942542f5fSchristos DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n", 231042542f5fSchristos __FUNCTION__, 231142542f5fSchristos draw->width, draw->height, 231242542f5fSchristos win->clipList.extents.x1, 231342542f5fSchristos win->clipList.extents.y1, 231442542f5fSchristos win->clipList.extents.x2, 231542542f5fSchristos win->clipList.extents.y2)); 231642542f5fSchristos return false; 231742542f5fSchristos } 231842542f5fSchristos 231942542f5fSchristos if (overlaps_other_crtc(sna, crtc)) { 232042542f5fSchristos DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__)); 232142542f5fSchristos return false; 232242542f5fSchristos } 232342542f5fSchristos 232442542f5fSchristos if (get_private(back)->size != (draw->height << 16 | draw->width)) { 232542542f5fSchristos DBG(("%s: no, DRI2 buffers does not fit window\n", 232642542f5fSchristos __FUNCTION__)); 232742542f5fSchristos return false; 232842542f5fSchristos } 232942542f5fSchristos 233042542f5fSchristos assert(win != win->drawable.pScreen->root); 233142542f5fSchristos DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 233242542f5fSchristos return true; 233342542f5fSchristos} 233442542f5fSchristos 233542542f5fSchristosstatic void 233642542f5fSchristossna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 233742542f5fSchristos{ 233842542f5fSchristos WindowPtr win = (WindowPtr)draw; 233942542f5fSchristos struct kgem_bo *back_bo, *front_bo; 234042542f5fSchristos PixmapPtr pixmap; 234142542f5fSchristos int tmp; 234242542f5fSchristos 234342542f5fSchristos assert(draw->type != DRAWABLE_PIXMAP); 234442542f5fSchristos pixmap = get_window_pixmap(win); 234542542f5fSchristos 234642542f5fSchristos back_bo = get_private(back)->bo; 234742542f5fSchristos front_bo = get_private(front)->bo; 234842542f5fSchristos 234963ef14f0Smrg DBG(("%s: win=%ld, exchange front=%d/%d,ref=%d and back=%d/%d,ref=%d, pixmap=%ld %dx%d\n", 235042542f5fSchristos __FUNCTION__, win->drawable.id, 235163ef14f0Smrg front_bo->handle, front->name, get_private(front)->refcnt, 235263ef14f0Smrg back_bo->handle, back->name, get_private(back)->refcnt, 235342542f5fSchristos pixmap->drawable.serialNumber, 235442542f5fSchristos pixmap->drawable.width, 235542542f5fSchristos pixmap->drawable.height)); 235642542f5fSchristos 235763ef14f0Smrg DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n", 235863ef14f0Smrg __FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout)); 235963ef14f0Smrg DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n", 236063ef14f0Smrg __FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout)); 236163ef14f0Smrg 236263ef14f0Smrg assert(front_bo != back_bo); 236342542f5fSchristos assert(front_bo->refcnt); 236442542f5fSchristos assert(back_bo->refcnt); 236542542f5fSchristos 236642542f5fSchristos assert(sna_pixmap_get_buffer(pixmap) == front); 236742542f5fSchristos 236842542f5fSchristos assert(pixmap->drawable.height * back_bo->pitch <= kgem_bo_size(back_bo)); 236942542f5fSchristos assert(pixmap->drawable.height * front_bo->pitch <= kgem_bo_size(front_bo)); 237042542f5fSchristos 237142542f5fSchristos set_bo(pixmap, back_bo); 237242542f5fSchristos 237342542f5fSchristos get_private(front)->bo = back_bo; 237442542f5fSchristos get_private(back)->bo = front_bo; 237513496ba1Ssnj mark_stale(back); 237642542f5fSchristos 237763ef14f0Smrg assert(front_bo->active_scanout > 0); 237863ef14f0Smrg front_bo->active_scanout--; 237963ef14f0Smrg back_bo->active_scanout++; 238063ef14f0Smrg assert(back_bo->active_scanout <= back_bo->refcnt); 238163ef14f0Smrg 238242542f5fSchristos tmp = front->name; 238342542f5fSchristos front->name = back->name; 238442542f5fSchristos back->name = tmp; 238542542f5fSchristos 238613496ba1Ssnj tmp = front->pitch; 238713496ba1Ssnj front->pitch = back->pitch; 238813496ba1Ssnj back->pitch = tmp; 238913496ba1Ssnj 239063ef14f0Smrg tmp = front->flags; 239163ef14f0Smrg front->flags = back->flags; 239263ef14f0Smrg back->flags = tmp; 239363ef14f0Smrg 239442542f5fSchristos assert(front_bo->refcnt); 239542542f5fSchristos assert(back_bo->refcnt); 239642542f5fSchristos 239763ef14f0Smrg assert(front_bo->pitch == get_private(front)->bo->pitch); 239863ef14f0Smrg assert(back_bo->pitch == get_private(back)->bo->pitch); 239963ef14f0Smrg 240042542f5fSchristos assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo); 240142542f5fSchristos} 240242542f5fSchristos 240342542f5fSchristosstatic void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back) 240442542f5fSchristos{ 240542542f5fSchristos WindowPtr win = (WindowPtr)draw; 240663ef14f0Smrg struct dri2_window *priv = dri2_window(win); 240742542f5fSchristos 240842542f5fSchristos DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n", 240942542f5fSchristos __FUNCTION__, 241042542f5fSchristos get_private(front)->bo->handle, front->name, 241142542f5fSchristos get_private(back)->bo->handle, back->name, 241242542f5fSchristos win->drawable.id, 241342542f5fSchristos get_window_pixmap(win)->drawable.serialNumber, 241442542f5fSchristos get_window_pixmap(win)->drawable.width, 241542542f5fSchristos get_window_pixmap(win)->drawable.height)); 241663ef14f0Smrg assert(can_xchg_crtc(sna, draw, crtc, front, back)); 241742542f5fSchristos 241863ef14f0Smrg if (APPLY_DAMAGE) { 241963ef14f0Smrg DBG(("%s: marking drawable as damaged\n", __FUNCTION__)); 242063ef14f0Smrg sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE; 242163ef14f0Smrg DamageRegionAppend(&win->drawable, &win->clipList); 242263ef14f0Smrg } 242342542f5fSchristos sna_shadow_set_crtc(sna, crtc, get_private(back)->bo); 242463ef14f0Smrg if (APPLY_DAMAGE) { 242563ef14f0Smrg sna->ignore_copy_area = false; 242663ef14f0Smrg DamageRegionProcessPending(&win->drawable); 242763ef14f0Smrg } 242842542f5fSchristos 242963ef14f0Smrg if (priv->front == NULL) { 243063ef14f0Smrg DRI2Buffer2Ptr tmp; 243142542f5fSchristos 243263ef14f0Smrg tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private)); 243363ef14f0Smrg if (tmp == NULL) { 243463ef14f0Smrg sna_shadow_unset_crtc(sna, crtc); 243563ef14f0Smrg return; 243642542f5fSchristos } 243742542f5fSchristos 243863ef14f0Smrg tmp->attachment = DRI2BufferFrontLeft; 243963ef14f0Smrg tmp->driverPrivate = tmp + 1; 244063ef14f0Smrg tmp->cpp = back->cpp; 244163ef14f0Smrg tmp->format = back->format; 244263ef14f0Smrg 244363ef14f0Smrg get_private(tmp)->refcnt = 1; 244463ef14f0Smrg get_private(tmp)->bo = kgem_create_2d(&sna->kgem, 244563ef14f0Smrg draw->width, draw->height, draw->bitsPerPixel, 244663ef14f0Smrg get_private(back)->bo->tiling, 244763ef14f0Smrg CREATE_SCANOUT | CREATE_EXACT); 244863ef14f0Smrg if (get_private(tmp)->bo != NULL) { 244963ef14f0Smrg tmp->pitch = get_private(tmp)->bo->pitch; 245063ef14f0Smrg tmp->name = kgem_bo_flink(&sna->kgem, get_private(tmp)->bo); 245163ef14f0Smrg } 245263ef14f0Smrg if (tmp->name == 0) { 245363ef14f0Smrg if (get_private(tmp)->bo != NULL) 245463ef14f0Smrg kgem_bo_destroy(&sna->kgem, get_private(tmp)->bo); 245563ef14f0Smrg sna_shadow_unset_crtc(sna, crtc); 245663ef14f0Smrg return; 245763ef14f0Smrg } 245863ef14f0Smrg get_private(tmp)->size = get_private(back)->size; 245963ef14f0Smrg get_private(tmp)->pixmap = get_private(front)->pixmap; 246063ef14f0Smrg get_private(tmp)->proxy = sna_dri2_reference_buffer(front); 246163ef14f0Smrg get_private(tmp)->bo->active_scanout++; 246242542f5fSchristos 246363ef14f0Smrg priv->front = front = tmp; 246463ef14f0Smrg } 246563ef14f0Smrg assert(front == priv->front); 246642542f5fSchristos 246763ef14f0Smrg { 246863ef14f0Smrg struct kgem_bo *front_bo = get_private(front)->bo; 246963ef14f0Smrg struct kgem_bo *back_bo = get_private(back)->bo; 247063ef14f0Smrg unsigned tmp; 247142542f5fSchristos 247263ef14f0Smrg assert(front_bo->refcnt); 247363ef14f0Smrg assert(back_bo->refcnt); 247442542f5fSchristos 247563ef14f0Smrg get_private(back)->bo = front_bo; 247663ef14f0Smrg get_private(front)->bo = back_bo; 247763ef14f0Smrg mark_stale(back); 247842542f5fSchristos 247963ef14f0Smrg assert(front_bo->active_scanout > 0); 248063ef14f0Smrg front_bo->active_scanout--; 248163ef14f0Smrg back_bo->active_scanout++; 248263ef14f0Smrg assert(back_bo->active_scanout <= back_bo->refcnt); 248342542f5fSchristos 248463ef14f0Smrg tmp = front->name; 248563ef14f0Smrg front->name = back->name; 248663ef14f0Smrg back->name = tmp; 248742542f5fSchristos 248863ef14f0Smrg tmp = front->pitch; 248963ef14f0Smrg front->pitch = back->pitch; 249063ef14f0Smrg back->pitch = tmp; 249142542f5fSchristos 249263ef14f0Smrg tmp = front->flags; 249363ef14f0Smrg front->flags = back->flags; 249463ef14f0Smrg back->flags = tmp; 249563ef14f0Smrg } 249642542f5fSchristos} 249742542f5fSchristos 249813496ba1Ssnjstatic void chain_swap(struct sna_dri2_event *chain) 249942542f5fSchristos{ 250063ef14f0Smrg DBG(("%s: draw=%ld, queued?=%d, type=%d\n", 250163ef14f0Smrg __FUNCTION__, (long)chain->draw->id, chain->queued, chain->type)); 250263ef14f0Smrg 250363ef14f0Smrg if (chain->queued) /* too early! */ 250463ef14f0Smrg return; 250542542f5fSchristos 250642542f5fSchristos if (chain->draw == NULL) { 250713496ba1Ssnj sna_dri2_event_free(chain); 250842542f5fSchristos return; 250942542f5fSchristos } 251042542f5fSchristos 251142542f5fSchristos assert(chain == dri2_chain(chain->draw)); 251263ef14f0Smrg assert(chain->signal); 251342542f5fSchristos 251442542f5fSchristos switch (chain->type) { 251563ef14f0Smrg case SWAP_COMPLETE: 251642542f5fSchristos DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); 251713496ba1Ssnj if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) { 251842542f5fSchristos sna_dri2_xchg(chain->draw, chain->front, chain->back); 251963ef14f0Smrg } else if (can_xchg_crtc(chain->sna, chain->draw, chain->crtc, 252063ef14f0Smrg chain->front, chain->back)) { 252163ef14f0Smrg sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc, 252263ef14f0Smrg chain->front, chain->back); 252342542f5fSchristos } else { 252463ef14f0Smrg __sna_dri2_copy_event(chain, chain->sync | DRI2_BO); 252542542f5fSchristos } 252663ef14f0Smrg assert(get_private(chain->back)->bo != get_private(chain->front)->bo); 252742542f5fSchristos case SWAP: 252842542f5fSchristos break; 252942542f5fSchristos default: 253042542f5fSchristos return; 253142542f5fSchristos } 253242542f5fSchristos 253363ef14f0Smrg if ((chain->type == SWAP_COMPLETE && 253463ef14f0Smrg !swap_limit(chain->draw, 2 + !chain->sync) && 253563ef14f0Smrg !chain->sync) || 253663ef14f0Smrg !sna_next_vblank(chain)) { 253742542f5fSchristos DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__)); 253813496ba1Ssnj frame_swap_complete(chain, DRI2_BLIT_COMPLETE); 253913496ba1Ssnj sna_dri2_event_free(chain); 254042542f5fSchristos } 254142542f5fSchristos} 254242542f5fSchristos 254342542f5fSchristosstatic inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo) 254442542f5fSchristos{ 254542542f5fSchristos if (bo == NULL) 254642542f5fSchristos return false; 254742542f5fSchristos 254863ef14f0Smrg return __kgem_bo_is_busy(kgem, bo); 254942542f5fSchristos} 255042542f5fSchristos 255163ef14f0Smrgstatic bool sna_dri2_blit_complete(struct sna_dri2_event *info) 255242542f5fSchristos{ 255363ef14f0Smrg if (!info->bo) 255463ef14f0Smrg return true; 255542542f5fSchristos 255663ef14f0Smrg if (__kgem_bo_is_busy(&info->sna->kgem, info->bo)) { 255742542f5fSchristos DBG(("%s: vsync'ed blit is still busy, postponing\n", 255842542f5fSchristos __FUNCTION__)); 255963ef14f0Smrg if (sna_next_vblank(info)) 256042542f5fSchristos return false; 256163ef14f0Smrg 256263ef14f0Smrg kgem_bo_sync__gtt(&info->sna->kgem, info->bo); 256342542f5fSchristos } 256442542f5fSchristos 256542542f5fSchristos DBG(("%s: blit finished\n", __FUNCTION__)); 256663ef14f0Smrg kgem_bo_destroy(&info->sna->kgem, info->bo); 256763ef14f0Smrg info->bo = NULL; 256863ef14f0Smrg 256942542f5fSchristos return true; 257042542f5fSchristos} 257142542f5fSchristos 257213496ba1Ssnjvoid sna_dri2_vblank_handler(struct drm_event_vblank *event) 257342542f5fSchristos{ 257442542f5fSchristos struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data; 257513496ba1Ssnj struct sna *sna = info->sna; 257642542f5fSchristos DrawablePtr draw; 257742542f5fSchristos uint64_t msc; 257842542f5fSchristos 257963ef14f0Smrg DBG(("%s(type=%d, sequence=%d, draw=%ld)\n", __FUNCTION__, info->type, event->sequence, info->draw ? info->draw->serialNumber : 0)); 258042542f5fSchristos assert(info->queued); 258163ef14f0Smrg info->queued = false; 258263ef14f0Smrg 258342542f5fSchristos msc = sna_crtc_record_event(info->crtc, event); 258442542f5fSchristos 258542542f5fSchristos draw = info->draw; 258642542f5fSchristos if (draw == NULL) { 258742542f5fSchristos DBG(("%s -- drawable gone\n", __FUNCTION__)); 258842542f5fSchristos goto done; 258942542f5fSchristos } 259042542f5fSchristos 259163ef14f0Smrg assert((info->front == NULL && info->back == NULL) || info->front != info->back); 259242542f5fSchristos switch (info->type) { 259342542f5fSchristos case FLIP: 259442542f5fSchristos /* If we can still flip... */ 259563ef14f0Smrg assert(info->signal); 259642542f5fSchristos if (can_flip(sna, draw, info->front, info->back, info->crtc) && 259713496ba1Ssnj sna_dri2_flip(info)) 259842542f5fSchristos return; 259942542f5fSchristos 260042542f5fSchristos /* else fall through to blit */ 260142542f5fSchristos case SWAP: 260263ef14f0Smrg assert(info->signal); 260363ef14f0Smrg if (can_xchg(info->sna, draw, info->front, info->back)) { 260442542f5fSchristos sna_dri2_xchg(draw, info->front, info->back); 260563ef14f0Smrg info->type = SWAP_COMPLETE; 260663ef14f0Smrg } else if (can_xchg_crtc(sna, draw, info->crtc, 260763ef14f0Smrg info->front, info->back)) { 260863ef14f0Smrg sna_dri2_xchg_crtc(sna, draw, info->crtc, 260963ef14f0Smrg info->front, info->back); 261063ef14f0Smrg info->type = SWAP_COMPLETE; 261142542f5fSchristos } else { 261263ef14f0Smrg __sna_dri2_copy_event(info, DRI2_BO | DRI2_SYNC); 261363ef14f0Smrg info->type = SWAP_COMPLETE; 261442542f5fSchristos } 261542542f5fSchristos 261663ef14f0Smrg if (sna_next_vblank(info)) 261742542f5fSchristos return; 261842542f5fSchristos 261942542f5fSchristos DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno)); 262063ef14f0Smrg assert(info->pending.bo == NULL); 262163ef14f0Smrg assert(info->keepalive == 1); 262242542f5fSchristos /* fall through to SwapComplete */ 262363ef14f0Smrg case SWAP_COMPLETE: 262442542f5fSchristos DBG(("%s: %d complete, frame=%d tv=%d.%06d\n", 262542542f5fSchristos __FUNCTION__, info->type, 262642542f5fSchristos event->sequence, event->tv_sec, event->tv_usec)); 262742542f5fSchristos 262863ef14f0Smrg if (info->signal) { 262963ef14f0Smrg if (!sna_dri2_blit_complete(info)) 263042542f5fSchristos return; 263142542f5fSchristos 263242542f5fSchristos DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__, 263342542f5fSchristos event->sequence, event->tv_sec, event->tv_usec)); 263413496ba1Ssnj frame_swap_complete(info, DRI2_BLIT_COMPLETE); 263542542f5fSchristos } 263663ef14f0Smrg 263763ef14f0Smrg if (info->pending.bo) { 263863ef14f0Smrg struct copy current_back; 263963ef14f0Smrg 264063ef14f0Smrg DBG(("%s: swapping back handle=%d [name=%d, active=%d] for pending handle=%d [name=%d, active=%d], front handle=%d [name=%d, active=%d]\n", 264163ef14f0Smrg __FUNCTION__, 264263ef14f0Smrg get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout, 264363ef14f0Smrg info->pending.bo->handle, info->pending.name, info->pending.bo->active_scanout, 264463ef14f0Smrg get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout)); 264563ef14f0Smrg 264663ef14f0Smrg assert(info->pending.bo->active_scanout > 0); 264763ef14f0Smrg info->pending.bo->active_scanout--; 264863ef14f0Smrg 264963ef14f0Smrg current_back.bo = get_private(info->back)->bo; 265063ef14f0Smrg current_back.size = get_private(info->back)->size; 265163ef14f0Smrg current_back.name = info->back->name; 265263ef14f0Smrg current_back.flags = info->back->flags; 265363ef14f0Smrg 265463ef14f0Smrg get_private(info->back)->bo = info->pending.bo; 265563ef14f0Smrg get_private(info->back)->size = info->pending.size; 265663ef14f0Smrg info->back->name = info->pending.name; 265763ef14f0Smrg info->back->pitch = info->pending.bo->pitch; 265863ef14f0Smrg info->back->flags = info->pending.flags; 265963ef14f0Smrg info->pending.bo = NULL; 266063ef14f0Smrg 266163ef14f0Smrg assert(get_private(info->back)->bo != get_private(info->front)->bo); 266263ef14f0Smrg 266363ef14f0Smrg if (can_xchg(info->sna, info->draw, info->front, info->back)) 266463ef14f0Smrg sna_dri2_xchg(info->draw, info->front, info->back); 266563ef14f0Smrg else if (can_xchg_crtc(info->sna, info->draw, info->crtc, 266663ef14f0Smrg info->front, info->back)) 266763ef14f0Smrg sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc, 266863ef14f0Smrg info->front, info->back); 266963ef14f0Smrg else 267063ef14f0Smrg __sna_dri2_copy_event(info, info->sync | DRI2_BO); 267163ef14f0Smrg 267263ef14f0Smrg sna_dri2_cache_bo(info->sna, info->draw, 267363ef14f0Smrg get_private(info->back)->bo, 267463ef14f0Smrg info->back->name, 267563ef14f0Smrg get_private(info->back)->size, 267663ef14f0Smrg info->back->flags); 267763ef14f0Smrg 267863ef14f0Smrg get_private(info->back)->bo = current_back.bo; 267963ef14f0Smrg get_private(info->back)->size = current_back.size; 268063ef14f0Smrg info->back->name = current_back.name; 268163ef14f0Smrg info->back->pitch = current_back.bo->pitch; 268263ef14f0Smrg info->back->flags = current_back.flags; 268363ef14f0Smrg 268463ef14f0Smrg DBG(("%s: restored current back handle=%d [name=%d, active=%d], active=%d], front handle=%d [name=%d, active=%d]\n", 268563ef14f0Smrg __FUNCTION__, 268663ef14f0Smrg get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout, 268763ef14f0Smrg get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout)); 268863ef14f0Smrg 268963ef14f0Smrg assert(info->draw); 269063ef14f0Smrg assert(!info->signal); 269163ef14f0Smrg info->keepalive++; 269263ef14f0Smrg info->signal = true; 269363ef14f0Smrg } 269463ef14f0Smrg 269563ef14f0Smrg if (--info->keepalive) { 269663ef14f0Smrg if (sna_next_vblank(info)) 269763ef14f0Smrg return; 269863ef14f0Smrg 269963ef14f0Smrg if (info->signal) { 270063ef14f0Smrg DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__, 270163ef14f0Smrg event->sequence, event->tv_sec, event->tv_usec)); 270263ef14f0Smrg frame_swap_complete(info, DRI2_BLIT_COMPLETE); 270363ef14f0Smrg } 270463ef14f0Smrg } 270542542f5fSchristos break; 270642542f5fSchristos 270742542f5fSchristos case WAITMSC: 270842542f5fSchristos assert(info->client); 270942542f5fSchristos DRI2WaitMSCComplete(info->client, draw, msc, 271042542f5fSchristos event->tv_sec, event->tv_usec); 271142542f5fSchristos break; 271242542f5fSchristos default: 271342542f5fSchristos xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 271442542f5fSchristos "%s: unknown vblank event received\n", __func__); 271542542f5fSchristos /* Unknown type */ 271642542f5fSchristos break; 271742542f5fSchristos } 271842542f5fSchristos 271942542f5fSchristos if (info->chain) { 272063ef14f0Smrg DBG(("%s: continuing chain\n", __FUNCTION__)); 272142542f5fSchristos assert(info->chain != info); 272242542f5fSchristos assert(info->draw == draw); 272363ef14f0Smrg sna_dri2_remove_event(info); 272413496ba1Ssnj chain_swap(info->chain); 272542542f5fSchristos } 272642542f5fSchristos 272742542f5fSchristosdone: 272813496ba1Ssnj sna_dri2_event_free(info); 272942542f5fSchristos DBG(("%s complete\n", __FUNCTION__)); 273042542f5fSchristos} 273142542f5fSchristos 273263ef14f0Smrgstatic void 273342542f5fSchristossna_dri2_immediate_blit(struct sna *sna, 273442542f5fSchristos struct sna_dri2_event *info, 273563ef14f0Smrg bool sync) 273642542f5fSchristos{ 273763ef14f0Smrg struct sna_dri2_event *chain = dri2_chain(info->draw); 273842542f5fSchristos 273942542f5fSchristos if (sna->flags & SNA_NO_WAIT) 274042542f5fSchristos sync = false; 274142542f5fSchristos 274263ef14f0Smrg DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, pipe %d\n", 274363ef14f0Smrg __FUNCTION__, sync, chain != info, info->pipe)); 274463ef14f0Smrg assert(chain); 274542542f5fSchristos 274663ef14f0Smrg info->type = SWAP_COMPLETE; 274763ef14f0Smrg info->sync = sync; 274863ef14f0Smrg info->keepalive = KEEPALIVE; 274942542f5fSchristos 275063ef14f0Smrg if (chain == info) { 275163ef14f0Smrg DBG(("%s: no pending blit, starting chain\n", __FUNCTION__)); 275263ef14f0Smrg 275363ef14f0Smrg assert(info->front != info->back); 275463ef14f0Smrg if (can_xchg(info->sna, info->draw, info->front, info->back)) { 275563ef14f0Smrg sna_dri2_xchg(info->draw, info->front, info->back); 275663ef14f0Smrg } else if (can_xchg_crtc(info->sna, info->draw, info->crtc, 275763ef14f0Smrg info->front, info->back)) { 275863ef14f0Smrg sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc, 275963ef14f0Smrg info->front, info->back); 276063ef14f0Smrg } else 276163ef14f0Smrg __sna_dri2_copy_event(info, sync | DRI2_BO); 276263ef14f0Smrg 276363ef14f0Smrg assert(info->signal); 276463ef14f0Smrg 276563ef14f0Smrg if ((!swap_limit(info->draw, 2 + !sync) && !sync) || 276663ef14f0Smrg !sna_next_vblank(info)) { 276763ef14f0Smrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 276863ef14f0Smrg frame_swap_complete(info, DRI2_BLIT_COMPLETE); 276963ef14f0Smrg sna_dri2_event_free(info); 277063ef14f0Smrg } 277163ef14f0Smrg return; 277263ef14f0Smrg } 277363ef14f0Smrg 277463ef14f0Smrg DBG(("%s: current event front=%d [name=%d, active?=%d], back=%d [name=%d, active?=%d]\n", __FUNCTION__, 277563ef14f0Smrg get_private(chain->front)->bo->handle, chain->front->name, get_private(chain->front)->bo->active_scanout, 277663ef14f0Smrg get_private(chain->back)->bo->handle, chain->back->name, get_private(chain->back)->bo->active_scanout)); 277763ef14f0Smrg 277863ef14f0Smrg if (chain->type == SWAP_COMPLETE && chain->front == info->front) { 277963ef14f0Smrg assert(chain->draw == info->draw); 278063ef14f0Smrg assert(chain->client == info->client); 278163ef14f0Smrg assert(chain->event_complete == info->event_complete); 278263ef14f0Smrg assert(chain->event_data == info->event_data); 278363ef14f0Smrg assert(chain->queued); 278463ef14f0Smrg 278563ef14f0Smrg if ((!sync || !chain->sync) && chain->pending.bo) { 278663ef14f0Smrg bool signal = chain->signal; 278763ef14f0Smrg 278863ef14f0Smrg DBG(("%s: swap elision, unblocking client\n", __FUNCTION__)); 278963ef14f0Smrg assert(chain->draw); 279063ef14f0Smrg chain->signal = true; 279163ef14f0Smrg frame_swap_complete(chain, DRI2_EXCHANGE_COMPLETE); 279263ef14f0Smrg chain->signal = signal; 279363ef14f0Smrg 279463ef14f0Smrg assert(chain->pending.bo->active_scanout > 0); 279563ef14f0Smrg chain->pending.bo->active_scanout--; 279663ef14f0Smrg 279763ef14f0Smrg sna_dri2_cache_bo(chain->sna, chain->draw, 279863ef14f0Smrg chain->pending.bo, 279963ef14f0Smrg chain->pending.name, 280063ef14f0Smrg chain->pending.size, 280163ef14f0Smrg chain->pending.flags); 280263ef14f0Smrg chain->pending.bo = NULL; 280363ef14f0Smrg } 280463ef14f0Smrg 280563ef14f0Smrg if (chain->pending.bo == NULL && swap_limit(info->draw, 2 + !sync)) { 280663ef14f0Smrg DBG(("%s: setting handle=%d as pending blit (current event front=%d, back=%d)\n", __FUNCTION__, 280763ef14f0Smrg get_private(info->back)->bo->handle, 280863ef14f0Smrg get_private(chain->front)->bo->handle, 280963ef14f0Smrg get_private(chain->back)->bo->handle)); 281063ef14f0Smrg chain->pending.bo = ref(get_private(info->back)->bo); 281163ef14f0Smrg chain->pending.size = get_private(info->back)->size; 281263ef14f0Smrg chain->pending.name = info->back->name; 281363ef14f0Smrg chain->pending.flags = info->back->flags; 281463ef14f0Smrg chain->sync = sync; 281563ef14f0Smrg info->signal = false; /* transfer signal to pending */ 281663ef14f0Smrg 281763ef14f0Smrg /* Prevent us from handing it back on next GetBuffers */ 281863ef14f0Smrg chain->pending.bo->active_scanout++; 281963ef14f0Smrg 282063ef14f0Smrg sna_dri2_event_free(info); 282163ef14f0Smrg return; 282242542f5fSchristos } 282342542f5fSchristos } 282442542f5fSchristos 282563ef14f0Smrg DBG(("%s: pending blit, chained\n", __FUNCTION__)); 282642542f5fSchristos} 282742542f5fSchristos 282842542f5fSchristosstatic bool 282913496ba1Ssnjsna_dri2_flip_continue(struct sna_dri2_event *info) 283042542f5fSchristos{ 283163ef14f0Smrg struct kgem_bo *bo = get_private(info->front)->bo; 283242542f5fSchristos 283363ef14f0Smrg DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue)); 283463ef14f0Smrg assert(info->flip_continue > 0); 283563ef14f0Smrg info->type = info->flip_continue; 283663ef14f0Smrg info->flip_continue = 0; 283742542f5fSchristos 283863ef14f0Smrg assert(!info->signal); 283963ef14f0Smrg info->signal = info->type == FLIP_THROTTLE && info->draw; 284042542f5fSchristos 284163ef14f0Smrg if (info->sna->mode.front_active == 0) 284263ef14f0Smrg return false; 284342542f5fSchristos 284463ef14f0Smrg if (bo != sna_pixmap(info->sna->front)->gpu_bo) 284563ef14f0Smrg return false; 284642542f5fSchristos 284763ef14f0Smrg assert(!info->queued); 284863ef14f0Smrg if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info)) 284963ef14f0Smrg return false; 285042542f5fSchristos 285163ef14f0Smrg DBG(("%s: queued flip=%p\n", __FUNCTION__, info)); 285263ef14f0Smrg assert(info->sna->dri2.flip_pending == NULL || 285363ef14f0Smrg info->sna->dri2.flip_pending == info); 285463ef14f0Smrg info->sna->dri2.flip_pending = info; 285563ef14f0Smrg info->queued = true; 285642542f5fSchristos 285763ef14f0Smrg return true; 285863ef14f0Smrg} 285942542f5fSchristos 286063ef14f0Smrgstatic bool 286163ef14f0Smrgsna_dri2_flip_keepalive(struct sna_dri2_event *info) 286263ef14f0Smrg{ 286363ef14f0Smrg DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1)); 286463ef14f0Smrg assert(info->keepalive > 0); 286563ef14f0Smrg if (!--info->keepalive) 286663ef14f0Smrg return false; 286742542f5fSchristos 286863ef14f0Smrg if (info->draw == NULL) 286963ef14f0Smrg return false; 287042542f5fSchristos 287163ef14f0Smrg DBG(("%s: marking next flip as complete\n", __FUNCTION__)); 287263ef14f0Smrg info->flip_continue = FLIP_COMPLETE; 287363ef14f0Smrg return sna_dri2_flip_continue(info); 287442542f5fSchristos} 287542542f5fSchristos 287642542f5fSchristosstatic void chain_flip(struct sna *sna) 287742542f5fSchristos{ 287842542f5fSchristos struct sna_dri2_event *chain = sna->dri2.flip_pending; 287942542f5fSchristos 288042542f5fSchristos assert(chain->type == FLIP); 288163ef14f0Smrg DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n", 288263ef14f0Smrg __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0)); 288342542f5fSchristos 288442542f5fSchristos sna->dri2.flip_pending = NULL; 288542542f5fSchristos if (chain->draw == NULL) { 288613496ba1Ssnj sna_dri2_event_free(chain); 288742542f5fSchristos return; 288842542f5fSchristos } 288942542f5fSchristos 289042542f5fSchristos assert(chain == dri2_chain(chain->draw)); 289142542f5fSchristos assert(!chain->queued); 289242542f5fSchristos 289342542f5fSchristos if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) && 289413496ba1Ssnj sna_dri2_flip(chain)) { 289542542f5fSchristos DBG(("%s: performing chained flip\n", __FUNCTION__)); 289642542f5fSchristos } else { 289742542f5fSchristos DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); 289863ef14f0Smrg __sna_dri2_copy_event(chain, DRI2_SYNC); 289942542f5fSchristos 290013496ba1Ssnj if (xorg_can_triple_buffer()) { 290163ef14f0Smrg chain->type = SWAP_COMPLETE; 290263ef14f0Smrg assert(chain->signal); 290363ef14f0Smrg if (sna_next_vblank(chain)) 290442542f5fSchristos return; 290542542f5fSchristos } 290642542f5fSchristos 290742542f5fSchristos DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__)); 290813496ba1Ssnj frame_swap_complete(chain, DRI2_BLIT_COMPLETE); 290913496ba1Ssnj sna_dri2_event_free(chain); 291042542f5fSchristos } 291142542f5fSchristos} 291242542f5fSchristos 291313496ba1Ssnjstatic void sna_dri2_flip_event(struct sna_dri2_event *flip) 291442542f5fSchristos{ 291513496ba1Ssnj struct sna *sna = flip->sna; 291613496ba1Ssnj 291763ef14f0Smrg DBG(("%s flip=%p (pipe=%d, event=%d, queued?=%d)\n", __FUNCTION__, flip, flip->pipe, flip->type, flip->queued)); 291863ef14f0Smrg if (!flip->queued) /* pageflip died whilst being queued */ 291963ef14f0Smrg return; 292063ef14f0Smrg flip->queued = false; 292142542f5fSchristos 292242542f5fSchristos if (sna->dri2.flip_pending == flip) 292342542f5fSchristos sna->dri2.flip_pending = NULL; 292442542f5fSchristos 292542542f5fSchristos /* We assume our flips arrive in order, so we don't check the frame */ 292642542f5fSchristos switch (flip->type) { 292742542f5fSchristos case FLIP: 292863ef14f0Smrg if (flip->signal) { 292963ef14f0Smrg DBG(("%s: swap complete, unblocking client\n", __FUNCTION__)); 293063ef14f0Smrg frame_swap_complete(flip, DRI2_FLIP_COMPLETE); 293163ef14f0Smrg } 293213496ba1Ssnj sna_dri2_event_free(flip); 293342542f5fSchristos 293442542f5fSchristos if (sna->dri2.flip_pending) 293542542f5fSchristos chain_flip(sna); 293642542f5fSchristos break; 293742542f5fSchristos 293842542f5fSchristos case FLIP_THROTTLE: 293963ef14f0Smrg if (flip->signal) { 294063ef14f0Smrg DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__)); 294163ef14f0Smrg frame_swap_complete(flip, DRI2_FLIP_COMPLETE); 294263ef14f0Smrg } 294342542f5fSchristos case FLIP_COMPLETE: 294463ef14f0Smrg assert(!flip->signal); 294542542f5fSchristos if (sna->dri2.flip_pending) { 294663ef14f0Smrg DBG(("%s: pending flip\n", __FUNCTION__)); 294713496ba1Ssnj sna_dri2_event_free(flip); 294842542f5fSchristos chain_flip(sna); 294963ef14f0Smrg } else if (!flip->flip_continue) { 295042542f5fSchristos DBG(("%s: flip chain complete\n", __FUNCTION__)); 295163ef14f0Smrg if (!sna_dri2_flip_keepalive(flip)) { 295263ef14f0Smrg if (flip->chain) { 295363ef14f0Smrg sna_dri2_remove_event(flip); 295463ef14f0Smrg chain_swap(flip->chain); 295563ef14f0Smrg } 295642542f5fSchristos 295763ef14f0Smrg sna_dri2_event_free(flip); 295842542f5fSchristos } 295913496ba1Ssnj } else if (!sna_dri2_flip_continue(flip)) { 296042542f5fSchristos DBG(("%s: no longer able to flip\n", __FUNCTION__)); 296163ef14f0Smrg if (flip->draw != NULL) 296263ef14f0Smrg __sna_dri2_copy_event(flip, 0); 296363ef14f0Smrg if (flip->signal) { 296463ef14f0Smrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 296563ef14f0Smrg frame_swap_complete(flip, DRI2_BLIT_COMPLETE); 296663ef14f0Smrg } 296763ef14f0Smrg sna_dri2_event_free(flip); 296842542f5fSchristos } 296942542f5fSchristos break; 297042542f5fSchristos 297142542f5fSchristos default: /* Unknown type */ 297242542f5fSchristos xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 297342542f5fSchristos "%s: unknown vblank event received\n", __func__); 297413496ba1Ssnj sna_dri2_event_free(flip); 297542542f5fSchristos if (sna->dri2.flip_pending) 297642542f5fSchristos chain_flip(sna); 297742542f5fSchristos break; 297842542f5fSchristos } 297942542f5fSchristos} 298042542f5fSchristos 298163ef14f0Smrgstatic int 298263ef14f0Smrgsna_query_vblank(struct sna *sna, xf86CrtcPtr crtc, union drm_wait_vblank *vbl) 298363ef14f0Smrg{ 298463ef14f0Smrg VG_CLEAR(*vbl); 298563ef14f0Smrg vbl->request.type = 298663ef14f0Smrg _DRM_VBLANK_RELATIVE | pipe_select(sna_crtc_pipe(crtc)); 298763ef14f0Smrg vbl->request.sequence = 0; 298863ef14f0Smrg 298963ef14f0Smrg return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl); 299063ef14f0Smrg} 299163ef14f0Smrg 299242542f5fSchristosstatic uint64_t 299342542f5fSchristosget_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc) 299442542f5fSchristos{ 299542542f5fSchristos union drm_wait_vblank vbl; 299663ef14f0Smrg uint64_t ret; 299742542f5fSchristos 299863ef14f0Smrg if (sna_query_vblank(sna, crtc, &vbl) == 0) 299942542f5fSchristos ret = sna_crtc_record_vblank(crtc, &vbl); 300063ef14f0Smrg else 300163ef14f0Smrg ret = sna_crtc_last_swap(crtc)->msc; 300242542f5fSchristos 300342542f5fSchristos return draw_current_msc(draw, crtc, ret); 300442542f5fSchristos} 300542542f5fSchristos 300642542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR) 300742542f5fSchristosstatic Bool find(pointer value, XID id, pointer cdata) 300842542f5fSchristos{ 300942542f5fSchristos return TRUE; 301042542f5fSchristos} 301142542f5fSchristos#endif 301242542f5fSchristos 301342542f5fSchristosstatic int use_triple_buffer(struct sna *sna, ClientPtr client, bool async) 301442542f5fSchristos{ 301542542f5fSchristos if ((sna->flags & SNA_TRIPLE_BUFFER) == 0) { 301642542f5fSchristos DBG(("%s: triple buffer disabled, using FLIP\n", __FUNCTION__)); 301742542f5fSchristos return FLIP; 301842542f5fSchristos } 301942542f5fSchristos 302042542f5fSchristos if (async) { 302142542f5fSchristos DBG(("%s: running async, using %s\n", __FUNCTION__, 302242542f5fSchristos sna->flags & SNA_HAS_ASYNC_FLIP ? "FLIP_ASYNC" : "FLIP_COMPLETE")); 302342542f5fSchristos return sna->flags & SNA_HAS_ASYNC_FLIP ? FLIP_ASYNC : FLIP_COMPLETE; 302442542f5fSchristos } 302542542f5fSchristos 302613496ba1Ssnj if (xorg_can_triple_buffer()) { 302742542f5fSchristos DBG(("%s: triple buffer enabled, using FLIP_THROTTLE\n", __FUNCTION__)); 302842542f5fSchristos return FLIP_THROTTLE; 302942542f5fSchristos } 303042542f5fSchristos 303142542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR) 303242542f5fSchristos /* Hack: Disable triple buffering for compositors */ 303342542f5fSchristos { 303442542f5fSchristos struct sna_client *priv = sna_client(client); 303542542f5fSchristos if (priv->is_compositor == 0) 303642542f5fSchristos priv->is_compositor = 303742542f5fSchristos LookupClientResourceComplex(client, 303842542f5fSchristos CompositeClientWindowType+1, 303942542f5fSchristos find, NULL) ? FLIP : FLIP_COMPLETE; 304042542f5fSchristos 304142542f5fSchristos DBG(("%s: fake triple buffer enabled?=%d using %s\n", __FUNCTION__, 304242542f5fSchristos priv->is_compositor != FLIP, priv->is_compositor == FLIP ? "FLIP" : "FLIP_COMPLETE")); 304342542f5fSchristos return priv->is_compositor; 304442542f5fSchristos } 304542542f5fSchristos#else 304642542f5fSchristos DBG(("%s: fake triple buffer enabled, using FLIP_COMPLETE\n", __FUNCTION__)); 304742542f5fSchristos return FLIP_COMPLETE; 304842542f5fSchristos#endif 304942542f5fSchristos} 305042542f5fSchristos 305142542f5fSchristosstatic bool immediate_swap(struct sna *sna, 305242542f5fSchristos DrawablePtr draw, 305342542f5fSchristos xf86CrtcPtr crtc, 305463ef14f0Smrg uint64_t *target_msc, 305563ef14f0Smrg uint64_t divisor, 305663ef14f0Smrg uint64_t remainder, 305742542f5fSchristos uint64_t *current_msc) 305842542f5fSchristos{ 305963ef14f0Smrg /* 306063ef14f0Smrg * If divisor is zero, or current_msc is smaller than target_msc 306163ef14f0Smrg * we just need to make sure target_msc passes before initiating 306263ef14f0Smrg * the swap. 306363ef14f0Smrg */ 306442542f5fSchristos if (divisor == 0) { 306542542f5fSchristos *current_msc = -1; 306642542f5fSchristos 306742542f5fSchristos if (sna->flags & SNA_NO_WAIT) { 306842542f5fSchristos DBG(("%s: yes, waits are disabled\n", __FUNCTION__)); 306942542f5fSchristos return true; 307042542f5fSchristos } 307142542f5fSchristos 307263ef14f0Smrg if (*target_msc) 307342542f5fSchristos *current_msc = get_current_msc(sna, draw, crtc); 307442542f5fSchristos 307542542f5fSchristos DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n", 307663ef14f0Smrg __FUNCTION__, (long)*current_msc, (long)*target_msc, 307763ef14f0Smrg (*current_msc >= *target_msc - 1) ? "yes" : "no")); 307863ef14f0Smrg return *current_msc >= *target_msc - 1; 307942542f5fSchristos } 308042542f5fSchristos 308142542f5fSchristos DBG(("%s: explicit waits requests, divisor=%ld\n", 308242542f5fSchristos __FUNCTION__, (long)divisor)); 308342542f5fSchristos *current_msc = get_current_msc(sna, draw, crtc); 308463ef14f0Smrg if (*current_msc >= *target_msc) { 308563ef14f0Smrg DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n", 308663ef14f0Smrg __FUNCTION__, 308763ef14f0Smrg (long long)*current_msc, 308863ef14f0Smrg (long long)*target_msc, 308963ef14f0Smrg (long long)divisor, 309063ef14f0Smrg (long long)remainder)); 309163ef14f0Smrg 309263ef14f0Smrg *target_msc = *current_msc + remainder - *current_msc % divisor; 309363ef14f0Smrg if (*target_msc <= *current_msc) 309463ef14f0Smrg *target_msc += divisor; 309563ef14f0Smrg } 309663ef14f0Smrg 309763ef14f0Smrg DBG(("%s: target_msc=%lld, current_msc=%lld, immediate?=%d\n", 309863ef14f0Smrg __FUNCTION__, (long long)*target_msc, (long long)*current_msc, 309963ef14f0Smrg *current_msc >= *target_msc - 1)); 310063ef14f0Smrg return *current_msc >= *target_msc - 1; 310142542f5fSchristos} 310242542f5fSchristos 310342542f5fSchristosstatic bool 310442542f5fSchristossna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, 310542542f5fSchristos DRI2BufferPtr front, DRI2BufferPtr back, 310663ef14f0Smrg bool immediate, CARD64 *target_msc, CARD64 current_msc, 310742542f5fSchristos DRI2SwapEventPtr func, void *data) 310842542f5fSchristos{ 310942542f5fSchristos struct sna *sna = to_sna_from_drawable(draw); 311042542f5fSchristos struct sna_dri2_event *info; 311142542f5fSchristos 311263ef14f0Smrg if (immediate) { 311363ef14f0Smrg bool signal = false; 311442542f5fSchristos info = sna->dri2.flip_pending; 311542542f5fSchristos DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n", 311663ef14f0Smrg __FUNCTION__, sna_crtc_pipe(crtc), 311763ef14f0Smrg info != NULL, info ? info->flip_continue : 0, 311842542f5fSchristos info && info->draw == draw)); 311942542f5fSchristos 312042542f5fSchristos if (info && info->draw == draw) { 312142542f5fSchristos assert(info->type != FLIP); 312263ef14f0Smrg assert(info->queued); 312363ef14f0Smrg assert(info->front != info->back); 312463ef14f0Smrg if (info->front != front) { 312563ef14f0Smrg assert(info->front != NULL); 312663ef14f0Smrg _sna_dri2_destroy_buffer(sna, draw, info->front); 312763ef14f0Smrg info->front = sna_dri2_reference_buffer(front); 312863ef14f0Smrg } 312942542f5fSchristos if (info->back != back) { 313063ef14f0Smrg assert(info->back != NULL); 313163ef14f0Smrg _sna_dri2_destroy_buffer(sna, draw, info->back); 313242542f5fSchristos info->back = sna_dri2_reference_buffer(back); 313342542f5fSchristos } 313463ef14f0Smrg assert(info->front != info->back); 313563ef14f0Smrg DBG(("%s: executing xchg of pending flip: flip_continue=%d, keepalive=%d, chain?=%d\n", __FUNCTION__, info->flip_continue, info->keepalive, current_msc < *target_msc)); 313663ef14f0Smrg sna_dri2_xchg(draw, front, back); 313763ef14f0Smrg info->keepalive = KEEPALIVE; 313863ef14f0Smrg if (xorg_can_triple_buffer() && 313963ef14f0Smrg current_msc < *target_msc) { 314042542f5fSchristos DBG(("%s: chaining flip\n", __FUNCTION__)); 314163ef14f0Smrg info->flip_continue = FLIP_THROTTLE; 314242542f5fSchristos goto out; 314363ef14f0Smrg } else { 314463ef14f0Smrg info->flip_continue = FLIP_COMPLETE; 314563ef14f0Smrg signal = info->signal; 314663ef14f0Smrg assert(info->draw); 314763ef14f0Smrg info->signal = true; 314863ef14f0Smrg goto new_back; 314942542f5fSchristos } 315042542f5fSchristos } 315142542f5fSchristos 315263ef14f0Smrg info = sna_dri2_add_event(sna, draw, client, crtc); 315342542f5fSchristos if (info == NULL) 315442542f5fSchristos return false; 315542542f5fSchristos 315642542f5fSchristos assert(info->crtc == crtc); 315742542f5fSchristos info->event_complete = func; 315842542f5fSchristos info->event_data = data; 315963ef14f0Smrg assert(info->draw); 316063ef14f0Smrg info->signal = true; 316142542f5fSchristos 316263ef14f0Smrg assert(front != back); 316342542f5fSchristos info->front = sna_dri2_reference_buffer(front); 316442542f5fSchristos info->back = sna_dri2_reference_buffer(back); 316542542f5fSchristos 316642542f5fSchristos if (sna->dri2.flip_pending) { 316742542f5fSchristos /* We need to first wait (one vblank) for the 316842542f5fSchristos * async flips to complete before this client 316942542f5fSchristos * can take over. 317042542f5fSchristos */ 317142542f5fSchristos DBG(("%s: queueing flip after pending completion\n", 317242542f5fSchristos __FUNCTION__)); 317363ef14f0Smrg info->type = FLIP; 317442542f5fSchristos sna->dri2.flip_pending = info; 317542542f5fSchristos current_msc++; 317663ef14f0Smrg } else if (sna->mode.flip_active) { 317763ef14f0Smrg DBG(("%s: %d outstanding flips from old client, queueing\n", 317863ef14f0Smrg __FUNCTION__, sna->mode.flip_active)); 317963ef14f0Smrg goto queue; 318042542f5fSchristos } else { 318163ef14f0Smrg info->type = use_triple_buffer(sna, client, *target_msc == 0); 318213496ba1Ssnj if (!sna_dri2_flip(info)) { 318342542f5fSchristos DBG(("%s: flip failed, falling back\n", __FUNCTION__)); 318463ef14f0Smrg info->signal = false; 318513496ba1Ssnj sna_dri2_event_free(info); 318642542f5fSchristos return false; 318742542f5fSchristos } 318863ef14f0Smrg assert(get_private(info->front)->bo->active_scanout); 318942542f5fSchristos } 319042542f5fSchristos 319163ef14f0Smrg swap_limit(draw, 1 + (info->type == FLIP_THROTTLE)); 319263ef14f0Smrg if (info->type >= FLIP_COMPLETE) { 319342542f5fSchristosnew_back: 319413496ba1Ssnj if (!xorg_can_triple_buffer()) 319563ef14f0Smrg sna_dri2_get_back(sna, draw, back); 319642542f5fSchristos DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 319713496ba1Ssnj frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE); 319863ef14f0Smrg assert(info->draw); 319963ef14f0Smrg info->signal = signal; 320042542f5fSchristos if (info->type == FLIP_ASYNC) 320113496ba1Ssnj sna_dri2_event_free(info); 320242542f5fSchristos } 320342542f5fSchristosout: 320442542f5fSchristos DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1)); 320542542f5fSchristos *target_msc = current_msc + 1; 320642542f5fSchristos return true; 320742542f5fSchristos } 320842542f5fSchristos 320963ef14f0Smrgqueue: 321063ef14f0Smrg if (KEEPALIVE > 1 && sna->dri2.flip_pending) { 321163ef14f0Smrg info = sna->dri2.flip_pending; 321263ef14f0Smrg info->keepalive = 1; 321363ef14f0Smrg } 321463ef14f0Smrg 321563ef14f0Smrg info = sna_dri2_add_event(sna, draw, client, crtc); 321642542f5fSchristos if (info == NULL) 321742542f5fSchristos return false; 321842542f5fSchristos 321942542f5fSchristos assert(info->crtc == crtc); 322042542f5fSchristos info->event_complete = func; 322142542f5fSchristos info->event_data = data; 322263ef14f0Smrg assert(info->draw); 322363ef14f0Smrg info->signal = true; 322442542f5fSchristos info->type = FLIP; 322542542f5fSchristos 322663ef14f0Smrg assert(front != back); 322742542f5fSchristos info->front = sna_dri2_reference_buffer(front); 322842542f5fSchristos info->back = sna_dri2_reference_buffer(back); 322942542f5fSchristos 323063ef14f0Smrg if (*target_msc <= current_msc + 1 && sna_dri2_flip(info)) { 323142542f5fSchristos *target_msc = current_msc + 1; 323242542f5fSchristos } else { 323342542f5fSchristos /* Account for 1 frame extra pageflip delay */ 323463ef14f0Smrg if (!sna_wait_vblank(info, 323563ef14f0Smrg draw_target_seq(draw, *target_msc - 1))) { 323663ef14f0Smrg info->signal = false; 323713496ba1Ssnj sna_dri2_event_free(info); 323842542f5fSchristos return false; 323942542f5fSchristos } 324042542f5fSchristos } 324142542f5fSchristos 324242542f5fSchristos DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc)); 324342542f5fSchristos swap_limit(draw, 1); 324442542f5fSchristos return true; 324542542f5fSchristos} 324642542f5fSchristos 324742542f5fSchristosstatic bool has_pending_events(struct sna *sna) 324842542f5fSchristos{ 324942542f5fSchristos struct pollfd pfd; 325042542f5fSchristos pfd.fd = sna->kgem.fd; 325142542f5fSchristos pfd.events = POLLIN; 325242542f5fSchristos return poll(&pfd, 1, 0) == 1; 325342542f5fSchristos} 325442542f5fSchristos 325542542f5fSchristos/* 325642542f5fSchristos * ScheduleSwap is responsible for requesting a DRM vblank event for the 325742542f5fSchristos * appropriate frame. 325842542f5fSchristos * 325942542f5fSchristos * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 326042542f5fSchristos * the vblank requested can simply be the last queued swap frame + the swap 326142542f5fSchristos * interval for the drawable. 326242542f5fSchristos * 326342542f5fSchristos * In the case of a page flip, we request an event for the last queued swap 326442542f5fSchristos * frame + swap interval - 1, since we'll need to queue the flip for the frame 326542542f5fSchristos * immediately following the received event. 326642542f5fSchristos * 326742542f5fSchristos * The client will be blocked if it tries to perform further GL commands 326842542f5fSchristos * after queueing a swap, though in the Intel case after queueing a flip, the 326942542f5fSchristos * client is free to queue more commands; they'll block in the kernel if 327042542f5fSchristos * they access buffers busy with the flip. 327142542f5fSchristos * 327242542f5fSchristos * When the swap is complete, the driver should call into the server so it 327342542f5fSchristos * can send any swap complete events that have been requested. 327442542f5fSchristos */ 327542542f5fSchristosstatic int 327642542f5fSchristossna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 327742542f5fSchristos DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 327842542f5fSchristos CARD64 remainder, DRI2SwapEventPtr func, void *data) 327942542f5fSchristos{ 328042542f5fSchristos struct sna *sna = to_sna_from_drawable(draw); 328142542f5fSchristos xf86CrtcPtr crtc = NULL; 328242542f5fSchristos struct sna_dri2_event *info = NULL; 328313496ba1Ssnj int type = DRI2_EXCHANGE_COMPLETE; 328442542f5fSchristos CARD64 current_msc; 328563ef14f0Smrg bool immediate; 328642542f5fSchristos 328763ef14f0Smrg DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d, active=%d) , front=%u (refs=%d/%d, flush=%d, active=%d)\n", 328842542f5fSchristos __FUNCTION__, 328942542f5fSchristos (long)draw->id, draw->width, draw->height, 329042542f5fSchristos get_drawable_pixmap(draw)->drawable.serialNumber, 329142542f5fSchristos get_drawable_pixmap(draw)->drawable.width, 329242542f5fSchristos get_drawable_pixmap(draw)->drawable.height, 329342542f5fSchristos get_private(back)->bo->handle, 329442542f5fSchristos get_private(back)->refcnt, 329542542f5fSchristos get_private(back)->bo->refcnt, 329642542f5fSchristos get_private(back)->bo->flush, 329763ef14f0Smrg get_private(back)->bo->active_scanout, 329842542f5fSchristos get_private(front)->bo->handle, 329942542f5fSchristos get_private(front)->refcnt, 330042542f5fSchristos get_private(front)->bo->refcnt, 330163ef14f0Smrg get_private(front)->bo->flush, 330263ef14f0Smrg get_private(front)->bo->active_scanout)); 330342542f5fSchristos 330442542f5fSchristos DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n", 330542542f5fSchristos __FUNCTION__, 330642542f5fSchristos (long long)*target_msc, 330742542f5fSchristos (long long)divisor, 330842542f5fSchristos (long long)remainder)); 330942542f5fSchristos 331063ef14f0Smrg assert(front != back); 331163ef14f0Smrg assert(get_private(front) != get_private(back)); 331263ef14f0Smrg 331342542f5fSchristos assert(get_private(front)->refcnt); 331442542f5fSchristos assert(get_private(back)->refcnt); 331542542f5fSchristos 331663ef14f0Smrg assert(get_private(back)->bo != get_private(front)->bo); 331742542f5fSchristos assert(get_private(front)->bo->refcnt); 331842542f5fSchristos assert(get_private(back)->bo->refcnt); 331942542f5fSchristos 332063ef14f0Smrg assert(get_private(front)->bo->active_scanout); 332163ef14f0Smrg assert(!get_private(back)->bo->active_scanout); 332263ef14f0Smrg 332313496ba1Ssnj if (get_private(front)->pixmap != get_drawable_pixmap(draw)) { 332413496ba1Ssnj DBG(("%s: decoupled DRI2 front pixmap=%ld, actual pixmap=%ld\n", 332513496ba1Ssnj __FUNCTION__, 332613496ba1Ssnj get_private(front)->pixmap->drawable.serialNumber, 332713496ba1Ssnj get_drawable_pixmap(draw)->drawable.serialNumber)); 332842542f5fSchristos goto skip; 332913496ba1Ssnj } 333042542f5fSchristos 333113496ba1Ssnj if (get_private(back)->stale) { 333213496ba1Ssnj DBG(("%s: stale back buffer\n", __FUNCTION__)); 333342542f5fSchristos goto skip; 333413496ba1Ssnj } 333542542f5fSchristos 333642542f5fSchristos if (draw->type != DRAWABLE_PIXMAP) { 333742542f5fSchristos WindowPtr win = (WindowPtr)draw; 333842542f5fSchristos struct dri2_window *priv = dri2_window(win); 333963ef14f0Smrg 334042542f5fSchristos if (priv->front) { 334163ef14f0Smrg front = priv->front; 334263ef14f0Smrg assert(front->attachment == DRI2BufferFrontLeft); 334363ef14f0Smrg assert(get_private(front)->refcnt); 334463ef14f0Smrg assert(get_private(front)->pixmap == get_drawable_pixmap(draw)); 334542542f5fSchristos } 334663ef14f0Smrg 334742542f5fSchristos if (win->clipList.extents.x2 <= win->clipList.extents.x1 || 334813496ba1Ssnj win->clipList.extents.y2 <= win->clipList.extents.y1) { 334913496ba1Ssnj DBG(("%s: window clipped (%d, %d), (%d, %d)\n", 335013496ba1Ssnj __FUNCTION__, 335113496ba1Ssnj win->clipList.extents.x1, 335213496ba1Ssnj win->clipList.extents.y1, 335313496ba1Ssnj win->clipList.extents.x2, 335413496ba1Ssnj win->clipList.extents.y2)); 335542542f5fSchristos goto skip; 335613496ba1Ssnj } 335742542f5fSchristos } 335842542f5fSchristos 335963ef14f0Smrg DBG(("%s: using front handle=%d, active_scanout?=%d, flush?=%d\n", __FUNCTION__, get_private(front)->bo->handle, get_private(front)->bo->active_scanout, sna_pixmap_from_drawable(draw)->flush)); 336063ef14f0Smrg assert(get_private(front)->bo->active_scanout); 336163ef14f0Smrg assert(sna_pixmap_from_drawable(draw)->flush); 336263ef14f0Smrg 336342542f5fSchristos /* Drawable not displayed... just complete the swap */ 336442542f5fSchristos if ((sna->flags & SNA_NO_WAIT) == 0) 336542542f5fSchristos crtc = sna_dri2_get_crtc(draw); 336642542f5fSchristos if (crtc == NULL) { 336742542f5fSchristos DBG(("%s: off-screen, immediate update\n", __FUNCTION__)); 336842542f5fSchristos goto blit; 336942542f5fSchristos } 337042542f5fSchristos 337142542f5fSchristos assert(draw->type != DRAWABLE_PIXMAP); 337242542f5fSchristos 337342542f5fSchristos while (dri2_chain(draw) && has_pending_events(sna)) { 337442542f5fSchristos DBG(("%s: flushing pending events\n", __FUNCTION__)); 337542542f5fSchristos sna_mode_wakeup(sna); 337642542f5fSchristos } 337742542f5fSchristos 337863ef14f0Smrg immediate = immediate_swap(sna, draw, crtc, 337942542f5fSchristos target_msc, divisor, remainder, 338063ef14f0Smrg ¤t_msc); 338142542f5fSchristos 338242542f5fSchristos if (can_flip(sna, draw, front, back, crtc) && 338342542f5fSchristos sna_dri2_schedule_flip(client, draw, crtc, front, back, 338463ef14f0Smrg immediate, target_msc, current_msc, 338542542f5fSchristos func, data)) 338642542f5fSchristos return TRUE; 338742542f5fSchristos 338863ef14f0Smrg info = sna_dri2_add_event(sna, draw, client, crtc); 338942542f5fSchristos if (!info) 339042542f5fSchristos goto blit; 339142542f5fSchristos 339242542f5fSchristos assert(info->crtc == crtc); 339342542f5fSchristos info->event_complete = func; 339442542f5fSchristos info->event_data = data; 339563ef14f0Smrg assert(info->draw); 339663ef14f0Smrg info->signal = true; 339742542f5fSchristos 339863ef14f0Smrg assert(front != back); 339942542f5fSchristos info->front = sna_dri2_reference_buffer(front); 340042542f5fSchristos info->back = sna_dri2_reference_buffer(back); 340142542f5fSchristos 340263ef14f0Smrg if (immediate) { 340342542f5fSchristos bool sync = current_msc < *target_msc; 340463ef14f0Smrg sna_dri2_immediate_blit(sna, info, sync); 340542542f5fSchristos *target_msc = current_msc + sync; 340663ef14f0Smrg DBG(("%s: reported target_msc=%llu\n", 340763ef14f0Smrg __FUNCTION__, *target_msc)); 340842542f5fSchristos return TRUE; 340942542f5fSchristos } 341042542f5fSchristos 341142542f5fSchristos info->type = SWAP; 341242542f5fSchristos if (*target_msc <= current_msc + 1) { 341342542f5fSchristos DBG(("%s: performing blit before queueing\n", __FUNCTION__)); 341463ef14f0Smrg __sna_dri2_copy_event(info, DRI2_SYNC); 341563ef14f0Smrg info->type = SWAP_COMPLETE; 341663ef14f0Smrg if (!sna_next_vblank(info)) 341763ef14f0Smrg goto fake; 341863ef14f0Smrg 341963ef14f0Smrg DBG(("%s: reported target_msc=%llu\n", 342063ef14f0Smrg __FUNCTION__, *target_msc)); 342142542f5fSchristos *target_msc = current_msc + 1; 342263ef14f0Smrg swap_limit(draw, 2); 342363ef14f0Smrg } else { 342463ef14f0Smrg if (!sna_wait_vblank(info, 342563ef14f0Smrg draw_target_seq(draw, *target_msc - 1))) 342663ef14f0Smrg goto blit; 342742542f5fSchristos 342863ef14f0Smrg DBG(("%s: reported target_msc=%llu (in)\n", 342963ef14f0Smrg __FUNCTION__, *target_msc)); 343063ef14f0Smrg swap_limit(draw, 1); 343163ef14f0Smrg } 343242542f5fSchristos 343342542f5fSchristos return TRUE; 343442542f5fSchristos 343542542f5fSchristosblit: 343642542f5fSchristos DBG(("%s -- blit\n", __FUNCTION__)); 343713496ba1Ssnj if (can_xchg(sna, draw, front, back)) { 343842542f5fSchristos sna_dri2_xchg(draw, front, back); 343913496ba1Ssnj } else { 344063ef14f0Smrg __sna_dri2_copy_region(sna, draw, NULL, back, front, 0); 344163ef14f0Smrg front->flags = back->flags; 344213496ba1Ssnj type = DRI2_BLIT_COMPLETE; 344313496ba1Ssnj } 344463ef14f0Smrg if (draw->type == DRAWABLE_PIXMAP) 344563ef14f0Smrg goto fake; 344642542f5fSchristosskip: 344742542f5fSchristos DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__)); 344863ef14f0Smrg if (crtc == NULL && (sna->flags & SNA_NO_WAIT) == 0) 344963ef14f0Smrg crtc = sna_primary_crtc(sna); 345063ef14f0Smrg if (crtc && sna_crtc_is_on(crtc)) { 345163ef14f0Smrg if (info == NULL) 345263ef14f0Smrg info = sna_dri2_add_event(sna, draw, client, crtc); 345363ef14f0Smrg if (info != dri2_chain(draw)) 345463ef14f0Smrg goto fake; 345563ef14f0Smrg 345663ef14f0Smrg assert(info->crtc == crtc); 345763ef14f0Smrg 345863ef14f0Smrg info->type = SWAP_COMPLETE; 345963ef14f0Smrg info->event_complete = func; 346063ef14f0Smrg info->event_data = data; 346163ef14f0Smrg assert(info->draw); 346263ef14f0Smrg info->signal = true; 346363ef14f0Smrg 346463ef14f0Smrg if (info->front == NULL) 346563ef14f0Smrg info->front = sna_dri2_reference_buffer(front); 346663ef14f0Smrg if (info->back == NULL) 346763ef14f0Smrg info->back = sna_dri2_reference_buffer(back); 346863ef14f0Smrg 346963ef14f0Smrg if (!sna_next_vblank(info)) 347063ef14f0Smrg goto fake; 347163ef14f0Smrg 347263ef14f0Smrg swap_limit(draw, 1); 347363ef14f0Smrg } else { 347463ef14f0Smrgfake: 347563ef14f0Smrg /* XXX Use a Timer to throttle the client? */ 347663ef14f0Smrg fake_swap_complete(sna, client, draw, crtc, type, func, data); 347763ef14f0Smrg if (info) { 347863ef14f0Smrg assert(info->draw); 347963ef14f0Smrg info->signal = false; 348063ef14f0Smrg sna_dri2_event_free(info); 348163ef14f0Smrg } 348263ef14f0Smrg } 348363ef14f0Smrg DBG(("%s: reported target_msc=%llu (in)\n", __FUNCTION__, *target_msc)); 348442542f5fSchristos return TRUE; 348542542f5fSchristos} 348642542f5fSchristos 348742542f5fSchristos/* 348842542f5fSchristos * Get current frame count and frame count timestamp, based on drawable's 348942542f5fSchristos * crtc. 349042542f5fSchristos */ 349142542f5fSchristosstatic int 349242542f5fSchristossna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 349342542f5fSchristos{ 349442542f5fSchristos struct sna *sna = to_sna_from_drawable(draw); 349542542f5fSchristos xf86CrtcPtr crtc = sna_dri2_get_crtc(draw); 349642542f5fSchristos const struct ust_msc *swap; 349763ef14f0Smrg union drm_wait_vblank vbl; 349842542f5fSchristos 349942542f5fSchristos DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id, 350063ef14f0Smrg crtc ? sna_crtc_pipe(crtc) : -1)); 350142542f5fSchristos 350263ef14f0Smrg /* Drawable not displayed, make up a *monotonic* value */ 350363ef14f0Smrg if (crtc == NULL) 350463ef14f0Smrg crtc = sna_primary_crtc(sna); 350563ef14f0Smrg if (crtc == NULL) 350663ef14f0Smrg return FALSE; 350742542f5fSchristos 350863ef14f0Smrg if (sna_query_vblank(sna, crtc, &vbl) == 0) 350963ef14f0Smrg sna_crtc_record_vblank(crtc, &vbl); 351042542f5fSchristos 351142542f5fSchristos swap = sna_crtc_last_swap(crtc); 351242542f5fSchristos *msc = draw_current_msc(draw, crtc, swap->msc); 351342542f5fSchristos *ust = ust64(swap->tv_sec, swap->tv_usec); 351463ef14f0Smrg DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__, 351563ef14f0Smrg (long long)*msc, swap->msc, (long long)*ust)); 351642542f5fSchristos return TRUE; 351742542f5fSchristos} 351842542f5fSchristos 351942542f5fSchristos/* 352042542f5fSchristos * Request a DRM event when the requested conditions will be satisfied. 352142542f5fSchristos * 352242542f5fSchristos * We need to handle the event and ask the server to wake up the client when 352342542f5fSchristos * we receive it. 352442542f5fSchristos */ 352542542f5fSchristosstatic int 352642542f5fSchristossna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 352742542f5fSchristos CARD64 divisor, CARD64 remainder) 352842542f5fSchristos{ 352942542f5fSchristos struct sna *sna = to_sna_from_drawable(draw); 353042542f5fSchristos struct sna_dri2_event *info = NULL; 353142542f5fSchristos xf86CrtcPtr crtc; 353242542f5fSchristos CARD64 current_msc; 353342542f5fSchristos const struct ust_msc *swap; 353442542f5fSchristos 353542542f5fSchristos crtc = sna_dri2_get_crtc(draw); 353642542f5fSchristos DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n", 353763ef14f0Smrg __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1, 353842542f5fSchristos (long long)target_msc, 353942542f5fSchristos (long long)divisor, 354042542f5fSchristos (long long)remainder)); 354142542f5fSchristos 354242542f5fSchristos /* Drawable not visible, return immediately */ 354342542f5fSchristos if (crtc == NULL) 354463ef14f0Smrg crtc = sna_primary_crtc(sna); 354563ef14f0Smrg if (crtc == NULL) 354663ef14f0Smrg return FALSE; 354742542f5fSchristos 354863ef14f0Smrg current_msc = get_current_msc(sna, draw, crtc); 354942542f5fSchristos 355042542f5fSchristos /* If target_msc already reached or passed, set it to 355142542f5fSchristos * current_msc to ensure we return a reasonable value back 355242542f5fSchristos * to the caller. This keeps the client from continually 355342542f5fSchristos * sending us MSC targets from the past by forcibly updating 355442542f5fSchristos * their count on this call. 355542542f5fSchristos */ 355642542f5fSchristos if (divisor == 0 && current_msc >= target_msc) 355742542f5fSchristos goto out_complete; 355842542f5fSchristos 355963ef14f0Smrg info = sna_dri2_add_event(sna, draw, client, crtc); 356042542f5fSchristos if (!info) 356142542f5fSchristos goto out_complete; 356242542f5fSchristos 356342542f5fSchristos assert(info->crtc == crtc); 356442542f5fSchristos info->type = WAITMSC; 356542542f5fSchristos 356642542f5fSchristos /* 356742542f5fSchristos * If divisor is zero, or current_msc is smaller than target_msc, 356842542f5fSchristos * we just need to make sure target_msc passes before waking up the 356942542f5fSchristos * client. Otherwise, compute the next msc to match divisor/remainder. 357042542f5fSchristos */ 357142542f5fSchristos if (divisor && current_msc >= target_msc) { 357242542f5fSchristos DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n", 357342542f5fSchristos __FUNCTION__, 357442542f5fSchristos (long long)current_msc, 357542542f5fSchristos (long long)target_msc, 357642542f5fSchristos (long long)divisor, 357742542f5fSchristos (long long)remainder)); 357842542f5fSchristos target_msc = current_msc + remainder - current_msc % divisor; 357942542f5fSchristos if (target_msc <= current_msc) 358042542f5fSchristos target_msc += divisor; 358142542f5fSchristos } 358242542f5fSchristos 358363ef14f0Smrg if (!sna_wait_vblank(info, draw_target_seq(draw, target_msc))) 358442542f5fSchristos goto out_free_info; 358542542f5fSchristos 358642542f5fSchristos DRI2BlockClient(client, draw); 358742542f5fSchristos return TRUE; 358842542f5fSchristos 358942542f5fSchristosout_free_info: 359013496ba1Ssnj sna_dri2_event_free(info); 359142542f5fSchristosout_complete: 359242542f5fSchristos swap = sna_crtc_last_swap(crtc); 359342542f5fSchristos DRI2WaitMSCComplete(client, draw, 359442542f5fSchristos draw_current_msc(draw, crtc, swap->msc), 359542542f5fSchristos swap->tv_sec, swap->tv_usec); 359642542f5fSchristos return TRUE; 359742542f5fSchristos} 359842542f5fSchristos#else 359942542f5fSchristosvoid sna_dri2_destroy_window(WindowPtr win) { } 360013496ba1Ssnjvoid sna_dri2_decouple_window(WindowPtr win) { } 360142542f5fSchristos#endif 360242542f5fSchristos 360342542f5fSchristosstatic bool has_i830_dri(void) 360442542f5fSchristos{ 360542542f5fSchristos return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 360642542f5fSchristos} 360742542f5fSchristos 360842542f5fSchristosstatic int 360942542f5fSchristosnamecmp(const char *s1, const char *s2) 361042542f5fSchristos{ 361142542f5fSchristos char c1, c2; 361242542f5fSchristos 361342542f5fSchristos if (!s1 || *s1 == 0) { 361442542f5fSchristos if (!s2 || *s2 == 0) 361542542f5fSchristos return 0; 361642542f5fSchristos else 361742542f5fSchristos return 1; 361842542f5fSchristos } 361942542f5fSchristos 362042542f5fSchristos while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 362142542f5fSchristos s1++; 362242542f5fSchristos 362342542f5fSchristos while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 362442542f5fSchristos s2++; 362542542f5fSchristos 362642542f5fSchristos c1 = isupper(*s1) ? tolower(*s1) : *s1; 362742542f5fSchristos c2 = isupper(*s2) ? tolower(*s2) : *s2; 362842542f5fSchristos while (c1 == c2) { 362942542f5fSchristos if (c1 == '\0') 363042542f5fSchristos return 0; 363142542f5fSchristos 363242542f5fSchristos s1++; 363342542f5fSchristos while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 363442542f5fSchristos s1++; 363542542f5fSchristos 363642542f5fSchristos s2++; 363742542f5fSchristos while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 363842542f5fSchristos s2++; 363942542f5fSchristos 364042542f5fSchristos c1 = isupper(*s1) ? tolower(*s1) : *s1; 364142542f5fSchristos c2 = isupper(*s2) ? tolower(*s2) : *s2; 364242542f5fSchristos } 364342542f5fSchristos 364442542f5fSchristos return c1 - c2; 364542542f5fSchristos} 364642542f5fSchristos 364742542f5fSchristosstatic bool is_level(const char **str) 364842542f5fSchristos{ 364942542f5fSchristos const char *s = *str; 365042542f5fSchristos char *end; 365142542f5fSchristos unsigned val; 365242542f5fSchristos 365342542f5fSchristos if (s == NULL || *s == '\0') 365442542f5fSchristos return true; 365542542f5fSchristos 365642542f5fSchristos if (namecmp(s, "on") == 0) 365742542f5fSchristos return true; 365842542f5fSchristos if (namecmp(s, "true") == 0) 365942542f5fSchristos return true; 366042542f5fSchristos if (namecmp(s, "yes") == 0) 366142542f5fSchristos return true; 366242542f5fSchristos 366342542f5fSchristos if (namecmp(s, "0") == 0) 366442542f5fSchristos return true; 366542542f5fSchristos if (namecmp(s, "off") == 0) 366642542f5fSchristos return true; 366742542f5fSchristos if (namecmp(s, "false") == 0) 366842542f5fSchristos return true; 366942542f5fSchristos if (namecmp(s, "no") == 0) 367042542f5fSchristos return true; 367142542f5fSchristos 367242542f5fSchristos val = strtoul(s, &end, 0); 367342542f5fSchristos if (val && *end == '\0') 367442542f5fSchristos return true; 367542542f5fSchristos if (val && *end == ':') 367642542f5fSchristos *str = end + 1; 367742542f5fSchristos return false; 367842542f5fSchristos} 367942542f5fSchristos 368063ef14f0Smrgstatic const char *options_get_dri(struct sna *sna) 368163ef14f0Smrg{ 368263ef14f0Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 368363ef14f0Smrg return xf86GetOptValString(sna->Options, OPTION_DRI); 368463ef14f0Smrg#else 368563ef14f0Smrg return NULL; 368663ef14f0Smrg#endif 368763ef14f0Smrg} 368863ef14f0Smrg 368942542f5fSchristosstatic const char *dri_driver_name(struct sna *sna) 369042542f5fSchristos{ 369163ef14f0Smrg const char *s = options_get_dri(sna); 369242542f5fSchristos 369342542f5fSchristos if (is_level(&s)) { 369442542f5fSchristos if (sna->kgem.gen < 030) 369542542f5fSchristos return has_i830_dri() ? "i830" : "i915"; 369642542f5fSchristos else if (sna->kgem.gen < 040) 369742542f5fSchristos return "i915"; 369842542f5fSchristos else 369942542f5fSchristos return "i965"; 370042542f5fSchristos } 370142542f5fSchristos 370242542f5fSchristos return s; 370342542f5fSchristos} 370442542f5fSchristos 370542542f5fSchristosbool sna_dri2_open(struct sna *sna, ScreenPtr screen) 370642542f5fSchristos{ 370742542f5fSchristos DRI2InfoRec info; 370842542f5fSchristos int major = 1, minor = 0; 370942542f5fSchristos#if DRI2INFOREC_VERSION >= 4 371042542f5fSchristos const char *driverNames[2]; 371142542f5fSchristos#endif 371242542f5fSchristos 371342542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 371442542f5fSchristos 371542542f5fSchristos if (wedged(sna)) { 371642542f5fSchristos xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 371763ef14f0Smrg "loading DRI2 whilst acceleration is disabled.\n"); 371842542f5fSchristos } 371942542f5fSchristos 372042542f5fSchristos if (xf86LoaderCheckSymbol("DRI2Version")) 372142542f5fSchristos DRI2Version(&major, &minor); 372242542f5fSchristos 372342542f5fSchristos if (minor < 1) { 372442542f5fSchristos xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 372542542f5fSchristos "DRI2 requires DRI2 module version 1.1.0 or later\n"); 372642542f5fSchristos return false; 372742542f5fSchristos } 372842542f5fSchristos 372942542f5fSchristos memset(&info, '\0', sizeof(info)); 373042542f5fSchristos info.fd = sna->kgem.fd; 373142542f5fSchristos info.driverName = dri_driver_name(sna); 373263ef14f0Smrg info.deviceName = intel_get_master_name(sna->dev); 373342542f5fSchristos 373442542f5fSchristos DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n", 373542542f5fSchristos __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName)); 373642542f5fSchristos 373742542f5fSchristos#if DRI2INFOREC_VERSION == 2 373842542f5fSchristos /* The ABI between 2 and 3 was broken so we could get rid of 373942542f5fSchristos * the multi-buffer alloc functions. Make sure we indicate the 374042542f5fSchristos * right version so DRI2 can reject us if it's version 3 or above. */ 374142542f5fSchristos info.version = 2; 374242542f5fSchristos#else 374342542f5fSchristos info.version = 3; 374442542f5fSchristos#endif 374542542f5fSchristos info.CreateBuffer = sna_dri2_create_buffer; 374642542f5fSchristos info.DestroyBuffer = sna_dri2_destroy_buffer; 374742542f5fSchristos 374842542f5fSchristos info.CopyRegion = sna_dri2_copy_region; 374942542f5fSchristos#if DRI2INFOREC_VERSION >= 4 375042542f5fSchristos info.version = 4; 375142542f5fSchristos info.ScheduleSwap = sna_dri2_schedule_swap; 375242542f5fSchristos info.GetMSC = sna_dri2_get_msc; 375342542f5fSchristos info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc; 375442542f5fSchristos info.numDrivers = 2; 375542542f5fSchristos info.driverNames = driverNames; 375642542f5fSchristos driverNames[0] = info.driverName; 375763ef14f0Smrg driverNames[1] = "va_gl"; 375842542f5fSchristos#endif 375942542f5fSchristos 376042542f5fSchristos#if DRI2INFOREC_VERSION >= 6 376113496ba1Ssnj if (xorg_can_triple_buffer()) { 376263ef14f0Smrg DBG(("%s: enabling Xorg triple buffering\n", __FUNCTION__)); 376342542f5fSchristos info.version = 6; 376442542f5fSchristos info.SwapLimitValidate = sna_dri2_swap_limit_validate; 376542542f5fSchristos info.ReuseBufferNotify = sna_dri2_reuse_buffer; 376642542f5fSchristos } 376742542f5fSchristos#endif 376842542f5fSchristos 376942542f5fSchristos#if USE_ASYNC_SWAP 377063ef14f0Smrg DBG(("%s: enabled async swap and buffer age\n", __FUNCTION__)); 377142542f5fSchristos info.version = 10; 377242542f5fSchristos info.scheduleSwap0 = 1; 377363ef14f0Smrg info.bufferAge = 1; 377442542f5fSchristos#endif 377542542f5fSchristos 377642542f5fSchristos return DRI2ScreenInit(screen, &info); 377742542f5fSchristos} 377842542f5fSchristos 377942542f5fSchristosvoid sna_dri2_close(struct sna *sna, ScreenPtr screen) 378042542f5fSchristos{ 378142542f5fSchristos DBG(("%s()\n", __FUNCTION__)); 378242542f5fSchristos DRI2CloseScreen(screen); 378342542f5fSchristos} 3784