sna_dri2.c revision 428d7b3d
1428d7b3dSmrg/************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrgCopyright 2001 VA Linux Systems Inc., Fremont, California. 4428d7b3dSmrgCopyright © 2002 by David Dawes 5428d7b3dSmrg 6428d7b3dSmrgAll Rights Reserved. 7428d7b3dSmrg 8428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a 9428d7b3dSmrgcopy of this software and associated documentation files (the "Software"), 10428d7b3dSmrgto deal in the Software without restriction, including without limitation 11428d7b3dSmrgon the rights to use, copy, modify, merge, publish, distribute, sub 12428d7b3dSmrglicense, and/or sell copies of the Software, and to permit persons to whom 13428d7b3dSmrgthe Software is furnished to do so, subject to the following conditions: 14428d7b3dSmrg 15428d7b3dSmrgThe above copyright notice and this permission notice (including the next 16428d7b3dSmrgparagraph) shall be included in all copies or substantial portions of the 17428d7b3dSmrgSoftware. 18428d7b3dSmrg 19428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20428d7b3dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21428d7b3dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22428d7b3dSmrgATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 23428d7b3dSmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24428d7b3dSmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25428d7b3dSmrgUSE OR OTHER DEALINGS IN THE SOFTWARE. 26428d7b3dSmrg 27428d7b3dSmrg**************************************************************************/ 28428d7b3dSmrg 29428d7b3dSmrg/* 30428d7b3dSmrg * Authors: Jeff Hartmann <jhartmann@valinux.com> 31428d7b3dSmrg * David Dawes <dawes@xfree86.org> 32428d7b3dSmrg * Keith Whitwell <keith@tungstengraphics.com> 33428d7b3dSmrg */ 34428d7b3dSmrg 35428d7b3dSmrg#ifdef HAVE_CONFIG_H 36428d7b3dSmrg#include "config.h" 37428d7b3dSmrg#endif 38428d7b3dSmrg 39428d7b3dSmrg#include <errno.h> 40428d7b3dSmrg#include <time.h> 41428d7b3dSmrg#include <string.h> 42428d7b3dSmrg#include <unistd.h> 43428d7b3dSmrg#include <poll.h> 44428d7b3dSmrg 45428d7b3dSmrg#include "sna.h" 46428d7b3dSmrg#include "intel_options.h" 47428d7b3dSmrg 48428d7b3dSmrg#include <xf86drm.h> 49428d7b3dSmrg#include <i915_drm.h> 50428d7b3dSmrg#include <dri2.h> 51428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) && defined(COMPOSITE) 52428d7b3dSmrg#include <compositeext.h> 53428d7b3dSmrg#define CHECK_FOR_COMPOSITOR 54428d7b3dSmrg#endif 55428d7b3dSmrg 56428d7b3dSmrg#define DBG_CAN_FLIP 1 57428d7b3dSmrg#define DBG_CAN_XCHG 1 58428d7b3dSmrg 59428d7b3dSmrg#define DBG_FORCE_COPY -1 /* KGEM_BLT or KGEM_3D */ 60428d7b3dSmrg 61428d7b3dSmrg#if DRI2INFOREC_VERSION < 2 62428d7b3dSmrg#error DRI2 version supported by the Xserver is too old 63428d7b3dSmrg#endif 64428d7b3dSmrg 65428d7b3dSmrgstatic inline struct kgem_bo *ref(struct kgem_bo *bo) 66428d7b3dSmrg{ 67428d7b3dSmrg return kgem_bo_reference(bo); 68428d7b3dSmrg} 69428d7b3dSmrg 70428d7b3dSmrgstruct sna_dri2_private { 71428d7b3dSmrg PixmapPtr pixmap; 72428d7b3dSmrg struct kgem_bo *bo; 73428d7b3dSmrg DRI2Buffer2Ptr proxy; 74428d7b3dSmrg bool stale; 75428d7b3dSmrg uint32_t size; 76428d7b3dSmrg int refcnt; 77428d7b3dSmrg}; 78428d7b3dSmrg 79428d7b3dSmrgstatic inline struct sna_dri2_private * 80428d7b3dSmrgget_private(void *buffer) 81428d7b3dSmrg{ 82428d7b3dSmrg return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1); 83428d7b3dSmrg} 84428d7b3dSmrg 85428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 86428d7b3dSmrgenum event_type { 87428d7b3dSmrg WAITMSC = 0, 88428d7b3dSmrg SWAP, 89428d7b3dSmrg SWAP_WAIT, 90428d7b3dSmrg SWAP_THROTTLE, 91428d7b3dSmrg FLIP, 92428d7b3dSmrg FLIP_THROTTLE, 93428d7b3dSmrg FLIP_COMPLETE, 94428d7b3dSmrg FLIP_ASYNC, 95428d7b3dSmrg}; 96428d7b3dSmrg 97428d7b3dSmrgstruct dri_bo { 98428d7b3dSmrg struct list link; 99428d7b3dSmrg struct kgem_bo *bo; 100428d7b3dSmrg uint32_t name; 101428d7b3dSmrg}; 102428d7b3dSmrg 103428d7b3dSmrgstruct sna_dri2_event { 104428d7b3dSmrg struct sna *sna; 105428d7b3dSmrg DrawablePtr draw; 106428d7b3dSmrg ClientPtr client; 107428d7b3dSmrg enum event_type type; 108428d7b3dSmrg xf86CrtcPtr crtc; 109428d7b3dSmrg int pipe; 110428d7b3dSmrg bool queued; 111428d7b3dSmrg 112428d7b3dSmrg /* for swaps & flips only */ 113428d7b3dSmrg DRI2SwapEventPtr event_complete; 114428d7b3dSmrg void *event_data; 115428d7b3dSmrg DRI2BufferPtr front; 116428d7b3dSmrg DRI2BufferPtr back; 117428d7b3dSmrg struct kgem_bo *bo; 118428d7b3dSmrg 119428d7b3dSmrg struct sna_dri2_event *chain; 120428d7b3dSmrg 121428d7b3dSmrg struct list cache; 122428d7b3dSmrg struct list link; 123428d7b3dSmrg 124428d7b3dSmrg int mode; 125428d7b3dSmrg}; 126428d7b3dSmrg 127428d7b3dSmrgstatic void sna_dri2_flip_event(struct sna_dri2_event *flip); 128428d7b3dSmrg 129428d7b3dSmrgstatic void 130428d7b3dSmrgsna_dri2_get_back(struct sna *sna, 131428d7b3dSmrg DrawablePtr draw, 132428d7b3dSmrg DRI2BufferPtr back, 133428d7b3dSmrg struct sna_dri2_event *info) 134428d7b3dSmrg{ 135428d7b3dSmrg struct kgem_bo *bo; 136428d7b3dSmrg uint32_t name; 137428d7b3dSmrg bool reuse; 138428d7b3dSmrg 139428d7b3dSmrg DBG(("%s: draw size=%dx%d, buffer size=%dx%d\n", 140428d7b3dSmrg __FUNCTION__, draw->width, draw->height, 141428d7b3dSmrg get_private(back)->size & 0xffff, get_private(back)->size >> 16)); 142428d7b3dSmrg reuse = (draw->height << 16 | draw->width) == get_private(back)->size; 143428d7b3dSmrg if (reuse) { 144428d7b3dSmrg bo = get_private(back)->bo; 145428d7b3dSmrg assert(bo->refcnt); 146428d7b3dSmrg DBG(("%s: back buffer handle=%d, scanout?=%d, refcnt=%d\n", 147428d7b3dSmrg __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt)); 148428d7b3dSmrg if (bo->active_scanout == 0) { 149428d7b3dSmrg DBG(("%s: reuse unattached back\n", __FUNCTION__)); 150428d7b3dSmrg get_private(back)->stale = false; 151428d7b3dSmrg return; 152428d7b3dSmrg } 153428d7b3dSmrg } 154428d7b3dSmrg 155428d7b3dSmrg bo = NULL; 156428d7b3dSmrg if (info) { 157428d7b3dSmrg struct dri_bo *c; 158428d7b3dSmrg list_for_each_entry(c, &info->cache, link) { 159428d7b3dSmrg if (c->bo && c->bo->scanout == 0) { 160428d7b3dSmrg bo = c->bo; 161428d7b3dSmrg name = c->name; 162428d7b3dSmrg DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle)); 163428d7b3dSmrg list_move_tail(&c->link, &info->cache); 164428d7b3dSmrg c->bo = NULL; 165428d7b3dSmrg } 166428d7b3dSmrg } 167428d7b3dSmrg } 168428d7b3dSmrg if (bo == NULL) { 169428d7b3dSmrg DBG(("%s: allocating new backbuffer\n", __FUNCTION__)); 170428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 171428d7b3dSmrg draw->width, draw->height, draw->bitsPerPixel, 172428d7b3dSmrg get_private(back)->bo->tiling, 173428d7b3dSmrg get_private(back)->bo->scanout ? CREATE_SCANOUT : 0); 174428d7b3dSmrg if (bo == NULL) 175428d7b3dSmrg return; 176428d7b3dSmrg 177428d7b3dSmrg name = kgem_bo_flink(&sna->kgem, bo); 178428d7b3dSmrg if (name == 0) { 179428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 180428d7b3dSmrg return; 181428d7b3dSmrg } 182428d7b3dSmrg } 183428d7b3dSmrg assert(bo->active_scanout == 0); 184428d7b3dSmrg 185428d7b3dSmrg if (info && reuse) { 186428d7b3dSmrg bool found = false; 187428d7b3dSmrg struct dri_bo *c; 188428d7b3dSmrg 189428d7b3dSmrg list_for_each_entry_reverse(c, &info->cache, link) { 190428d7b3dSmrg if (c->bo == NULL) { 191428d7b3dSmrg found = true; 192428d7b3dSmrg _list_del(&c->link); 193428d7b3dSmrg break; 194428d7b3dSmrg } 195428d7b3dSmrg } 196428d7b3dSmrg if (!found) 197428d7b3dSmrg c = malloc(sizeof(*c)); 198428d7b3dSmrg if (c != NULL) { 199428d7b3dSmrg c->bo = ref(get_private(back)->bo); 200428d7b3dSmrg c->name = back->name; 201428d7b3dSmrg list_add(&c->link, &info->cache); 202428d7b3dSmrg DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name)); 203428d7b3dSmrg } 204428d7b3dSmrg } 205428d7b3dSmrg 206428d7b3dSmrg assert(bo != get_private(back)->bo); 207428d7b3dSmrg kgem_bo_destroy(&sna->kgem, get_private(back)->bo); 208428d7b3dSmrg 209428d7b3dSmrg get_private(back)->bo = bo; 210428d7b3dSmrg get_private(back)->size = draw->height << 16 | draw->width; 211428d7b3dSmrg back->pitch = bo->pitch; 212428d7b3dSmrg back->name = name; 213428d7b3dSmrg 214428d7b3dSmrg get_private(back)->stale = false; 215428d7b3dSmrg} 216428d7b3dSmrg 217428d7b3dSmrgstruct dri2_window { 218428d7b3dSmrg DRI2BufferPtr front; 219428d7b3dSmrg struct sna_dri2_event *chain; 220428d7b3dSmrg xf86CrtcPtr crtc; 221428d7b3dSmrg int64_t msc_delta; 222428d7b3dSmrg}; 223428d7b3dSmrg 224428d7b3dSmrgstatic struct dri2_window *dri2_window(WindowPtr win) 225428d7b3dSmrg{ 226428d7b3dSmrg assert(win->drawable.type != DRAWABLE_PIXMAP); 227428d7b3dSmrg return ((void **)__get_private(win, sna_window_key))[1]; 228428d7b3dSmrg} 229428d7b3dSmrg 230428d7b3dSmrgstatic struct sna_dri2_event * 231428d7b3dSmrgdri2_chain(DrawablePtr d) 232428d7b3dSmrg{ 233428d7b3dSmrg struct dri2_window *priv = dri2_window((WindowPtr)d); 234428d7b3dSmrg assert(priv != NULL); 235428d7b3dSmrg return priv->chain; 236428d7b3dSmrg} 237428d7b3dSmrginline static DRI2BufferPtr dri2_window_get_front(WindowPtr win) 238428d7b3dSmrg{ 239428d7b3dSmrg struct dri2_window *priv = dri2_window(win); 240428d7b3dSmrg return priv ? priv->front : NULL; 241428d7b3dSmrg} 242428d7b3dSmrg#else 243428d7b3dSmrginline static void *dri2_window_get_front(WindowPtr win) { return NULL; } 244428d7b3dSmrg#endif 245428d7b3dSmrg 246428d7b3dSmrg#if DRI2INFOREC_VERSION < 6 247428d7b3dSmrg 248428d7b3dSmrg#define xorg_can_triple_buffer() 0 249428d7b3dSmrg#define swap_limit(d, l) false 250428d7b3dSmrg#define mark_stale(b) 251428d7b3dSmrg 252428d7b3dSmrg#else 253428d7b3dSmrg 254428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,904,0) 255428d7b3dSmrg/* Prime fixed for triple buffer support */ 256428d7b3dSmrg#define xorg_can_triple_buffer() 1 257428d7b3dSmrg#elif XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,12,99,901,0) 258428d7b3dSmrg/* Before numGPUScreens was introduced */ 259428d7b3dSmrg#define xorg_can_triple_buffer() 1 260428d7b3dSmrg#else 261428d7b3dSmrg/* Subject to crashers when combining triple buffering and Prime */ 262428d7b3dSmrginline static bool xorg_can_triple_buffer(void) 263428d7b3dSmrg{ 264428d7b3dSmrg return screenInfo.numGPUScreens == 0; 265428d7b3dSmrg} 266428d7b3dSmrg#endif 267428d7b3dSmrg 268428d7b3dSmrgstatic void 269428d7b3dSmrgmark_stale(DRI2BufferPtr back) 270428d7b3dSmrg{ 271428d7b3dSmrg /* If we have reuse notifications, we can track when the 272428d7b3dSmrg * client tries to present an old buffer (one that has not 273428d7b3dSmrg * been updated since the last swap) and avoid showing the 274428d7b3dSmrg * stale frame. (This is mostly useful for tracking down 275428d7b3dSmrg * driver bugs!) 276428d7b3dSmrg */ 277428d7b3dSmrg get_private(back)->stale = xorg_can_triple_buffer(); 278428d7b3dSmrg} 279428d7b3dSmrg 280428d7b3dSmrgstatic Bool 281428d7b3dSmrgsna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit) 282428d7b3dSmrg{ 283428d7b3dSmrg DBG(("%s: swap limit set to %d\n", __FUNCTION__, swap_limit)); 284428d7b3dSmrg return swap_limit >= 1; 285428d7b3dSmrg} 286428d7b3dSmrg 287428d7b3dSmrgstatic void 288428d7b3dSmrgsna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer) 289428d7b3dSmrg{ 290428d7b3dSmrg DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n", 291428d7b3dSmrg __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber, 292428d7b3dSmrg buffer->attachment, get_private(buffer)->bo->handle, buffer->name)); 293428d7b3dSmrg assert(get_private(buffer)->refcnt); 294428d7b3dSmrg assert(get_private(buffer)->bo->refcnt > get_private(buffer)->bo->active_scanout); 295428d7b3dSmrg 296428d7b3dSmrg if (buffer->attachment == DRI2BufferBackLeft && 297428d7b3dSmrg draw->type != DRAWABLE_PIXMAP) { 298428d7b3dSmrg DBG(("%s: replacing back buffer\n", __FUNCTION__)); 299428d7b3dSmrg sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw)); 300428d7b3dSmrg 301428d7b3dSmrg assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name); 302428d7b3dSmrg assert(get_private(buffer)->bo->refcnt); 303428d7b3dSmrg assert(get_private(buffer)->bo->active_scanout == 0); 304428d7b3dSmrg } 305428d7b3dSmrg} 306428d7b3dSmrg 307428d7b3dSmrgstatic bool swap_limit(DrawablePtr draw, int limit) 308428d7b3dSmrg{ 309428d7b3dSmrg if (!xorg_can_triple_buffer()) 310428d7b3dSmrg return false; 311428d7b3dSmrg 312428d7b3dSmrg DBG(("%s: draw=%ld setting swap limit to %d\n", __FUNCTION__, (long)draw->id, limit)); 313428d7b3dSmrg DRI2SwapLimit(draw, limit); 314428d7b3dSmrg return true; 315428d7b3dSmrg} 316428d7b3dSmrg#endif 317428d7b3dSmrg 318428d7b3dSmrg#if DRI2INFOREC_VERSION < 10 319428d7b3dSmrg#undef USE_ASYNC_SWAP 320428d7b3dSmrg#define USE_ASYNC_SWAP 0 321428d7b3dSmrg#endif 322428d7b3dSmrg 323428d7b3dSmrg#define COLOR_PREFER_TILING_Y 0 324428d7b3dSmrg 325428d7b3dSmrg/* Prefer to enable TILING_Y if this buffer will never be a 326428d7b3dSmrg * candidate for pageflipping 327428d7b3dSmrg */ 328428d7b3dSmrgstatic uint32_t color_tiling(struct sna *sna, DrawablePtr draw) 329428d7b3dSmrg{ 330428d7b3dSmrg uint32_t tiling; 331428d7b3dSmrg 332428d7b3dSmrg if (COLOR_PREFER_TILING_Y && 333428d7b3dSmrg (draw->width != sna->front->drawable.width || 334428d7b3dSmrg draw->height != sna->front->drawable.height)) 335428d7b3dSmrg tiling = I915_TILING_Y; 336428d7b3dSmrg else 337428d7b3dSmrg tiling = I915_TILING_X; 338428d7b3dSmrg 339428d7b3dSmrg return kgem_choose_tiling(&sna->kgem, -tiling, 340428d7b3dSmrg draw->width, 341428d7b3dSmrg draw->height, 342428d7b3dSmrg draw->bitsPerPixel); 343428d7b3dSmrg} 344428d7b3dSmrg 345428d7b3dSmrgstatic uint32_t other_tiling(struct sna *sna, DrawablePtr draw) 346428d7b3dSmrg{ 347428d7b3dSmrg /* XXX Can mix color X / depth Y? */ 348428d7b3dSmrg return kgem_choose_tiling(&sna->kgem, 349428d7b3dSmrg sna->kgem.gen >= 040 ? -I915_TILING_Y : -I915_TILING_X, 350428d7b3dSmrg draw->width, 351428d7b3dSmrg draw->height, 352428d7b3dSmrg draw->bitsPerPixel); 353428d7b3dSmrg} 354428d7b3dSmrg 355428d7b3dSmrgstatic struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, 356428d7b3dSmrg PixmapPtr pixmap) 357428d7b3dSmrg{ 358428d7b3dSmrg struct sna_pixmap *priv; 359428d7b3dSmrg int tiling; 360428d7b3dSmrg 361428d7b3dSmrg DBG(("%s: attaching DRI client to pixmap=%ld\n", 362428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 363428d7b3dSmrg 364428d7b3dSmrg priv = sna_pixmap(pixmap); 365428d7b3dSmrg if (priv != NULL && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { 366428d7b3dSmrg DBG(("%s: SHM or unattached Pixmap, BadAlloc\n", __FUNCTION__)); 367428d7b3dSmrg return NULL; 368428d7b3dSmrg } 369428d7b3dSmrg 370428d7b3dSmrg priv = sna_pixmap_move_to_gpu(pixmap, 371428d7b3dSmrg MOVE_READ | __MOVE_FORCE | __MOVE_DRI); 372428d7b3dSmrg if (priv == NULL) { 373428d7b3dSmrg DBG(("%s: failed to move to GPU, BadAlloc\n", __FUNCTION__)); 374428d7b3dSmrg return NULL; 375428d7b3dSmrg } 376428d7b3dSmrg 377428d7b3dSmrg assert(priv->flush == false); 378428d7b3dSmrg assert(priv->cpu_damage == NULL); 379428d7b3dSmrg assert(priv->gpu_bo); 380428d7b3dSmrg assert(priv->gpu_bo->proxy == NULL); 381428d7b3dSmrg assert(priv->gpu_bo->flush == false); 382428d7b3dSmrg 383428d7b3dSmrg tiling = color_tiling(sna, &pixmap->drawable); 384428d7b3dSmrg if (tiling < 0) 385428d7b3dSmrg tiling = -tiling; 386428d7b3dSmrg if (priv->gpu_bo->tiling != tiling) 387428d7b3dSmrg sna_pixmap_change_tiling(pixmap, tiling); 388428d7b3dSmrg 389428d7b3dSmrg return priv->gpu_bo; 390428d7b3dSmrg} 391428d7b3dSmrg 392428d7b3dSmrgpure static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap) 393428d7b3dSmrg{ 394428d7b3dSmrg assert(pixmap->refcnt); 395428d7b3dSmrg return ((void **)__get_private(pixmap, sna_pixmap_key))[2]; 396428d7b3dSmrg} 397428d7b3dSmrg 398428d7b3dSmrgstatic inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr) 399428d7b3dSmrg{ 400428d7b3dSmrg assert(pixmap->refcnt); 401428d7b3dSmrg ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr; 402428d7b3dSmrg} 403428d7b3dSmrg 404428d7b3dSmrgvoid 405428d7b3dSmrgsna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo) 406428d7b3dSmrg{ 407428d7b3dSmrg DRI2BufferPtr buffer; 408428d7b3dSmrg struct sna_dri2_private *private; 409428d7b3dSmrg 410428d7b3dSmrg buffer = sna_pixmap_get_buffer(pixmap); 411428d7b3dSmrg if (buffer == NULL) 412428d7b3dSmrg return; 413428d7b3dSmrg 414428d7b3dSmrg DBG(("%s: pixmap=%ld, old handle=%d, new handle=%d\n", __FUNCTION__, 415428d7b3dSmrg pixmap->drawable.serialNumber, 416428d7b3dSmrg get_private(buffer)->bo->handle, 417428d7b3dSmrg sna_pixmap(pixmap)->gpu_bo->handle)); 418428d7b3dSmrg 419428d7b3dSmrg private = get_private(buffer); 420428d7b3dSmrg assert(private->pixmap == pixmap); 421428d7b3dSmrg 422428d7b3dSmrg assert(bo != private->bo); 423428d7b3dSmrg if (private->bo == bo) 424428d7b3dSmrg return; 425428d7b3dSmrg 426428d7b3dSmrg DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle)); 427428d7b3dSmrg private->bo->flush = false; 428428d7b3dSmrg kgem_bo_destroy(&sna->kgem, private->bo); 429428d7b3dSmrg 430428d7b3dSmrg buffer->name = kgem_bo_flink(&sna->kgem, bo); 431428d7b3dSmrg buffer->pitch = bo->pitch; 432428d7b3dSmrg private->bo = ref(bo); 433428d7b3dSmrg 434428d7b3dSmrg DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle)); 435428d7b3dSmrg bo->flush = true; 436428d7b3dSmrg if (bo->exec) 437428d7b3dSmrg sna->kgem.flush = 1; 438428d7b3dSmrg assert(sna_pixmap(pixmap)->flush); 439428d7b3dSmrg 440428d7b3dSmrg /* XXX DRI2InvalidateDrawable(&pixmap->drawable); */ 441428d7b3dSmrg} 442428d7b3dSmrg 443428d7b3dSmrgstatic DRI2Buffer2Ptr 444428d7b3dSmrgsna_dri2_create_buffer(DrawablePtr draw, 445428d7b3dSmrg unsigned int attachment, 446428d7b3dSmrg unsigned int format) 447428d7b3dSmrg{ 448428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 449428d7b3dSmrg DRI2Buffer2Ptr buffer; 450428d7b3dSmrg struct sna_dri2_private *private; 451428d7b3dSmrg PixmapPtr pixmap; 452428d7b3dSmrg struct kgem_bo *bo; 453428d7b3dSmrg unsigned flags = 0; 454428d7b3dSmrg uint32_t size; 455428d7b3dSmrg int bpp; 456428d7b3dSmrg 457428d7b3dSmrg DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n", 458428d7b3dSmrg __FUNCTION__, 459428d7b3dSmrg get_drawable_pixmap(draw)->drawable.serialNumber, 460428d7b3dSmrg attachment, format, draw->width, draw->height, 461428d7b3dSmrg draw->type != DRAWABLE_PIXMAP)); 462428d7b3dSmrg 463428d7b3dSmrg pixmap = NULL; 464428d7b3dSmrg size = (uint32_t)draw->height << 16 | draw->width; 465428d7b3dSmrg switch (attachment) { 466428d7b3dSmrg case DRI2BufferFrontLeft: 467428d7b3dSmrg pixmap = get_drawable_pixmap(draw); 468428d7b3dSmrg buffer = NULL; 469428d7b3dSmrg if (draw->type != DRAWABLE_PIXMAP) 470428d7b3dSmrg buffer = dri2_window_get_front((WindowPtr)draw); 471428d7b3dSmrg if (buffer == NULL) 472428d7b3dSmrg buffer = sna_pixmap_get_buffer(pixmap); 473428d7b3dSmrg if (buffer) { 474428d7b3dSmrg private = get_private(buffer); 475428d7b3dSmrg 476428d7b3dSmrg DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d\n", 477428d7b3dSmrg __FUNCTION__, 478428d7b3dSmrg draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0, 479428d7b3dSmrg draw->width, draw->height, 480428d7b3dSmrg pixmap->drawable.serialNumber, 481428d7b3dSmrg private->pixmap->drawable.serialNumber, 482428d7b3dSmrg pixmap->drawable.width, 483428d7b3dSmrg pixmap->drawable.height, 484428d7b3dSmrg private->bo->handle, buffer->name)); 485428d7b3dSmrg 486428d7b3dSmrg assert(private->pixmap == pixmap); 487428d7b3dSmrg assert(sna_pixmap(pixmap)->flush); 488428d7b3dSmrg assert(sna_pixmap(pixmap)->pinned & PIN_DRI2); 489428d7b3dSmrg assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name); 490428d7b3dSmrg 491428d7b3dSmrg private->refcnt++; 492428d7b3dSmrg return buffer; 493428d7b3dSmrg } 494428d7b3dSmrg 495428d7b3dSmrg bo = sna_pixmap_set_dri(sna, pixmap); 496428d7b3dSmrg if (bo == NULL) 497428d7b3dSmrg return NULL; 498428d7b3dSmrg 499428d7b3dSmrg assert(sna_pixmap(pixmap) != NULL); 500428d7b3dSmrg 501428d7b3dSmrg bo = ref(bo); 502428d7b3dSmrg bpp = pixmap->drawable.bitsPerPixel; 503428d7b3dSmrg if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB)) 504428d7b3dSmrg flags |= CREATE_SCANOUT; 505428d7b3dSmrg DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n", 506428d7b3dSmrg __FUNCTION__, 507428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height, 508428d7b3dSmrg pixmap, pixmap->refcnt, flags & CREATE_SCANOUT)); 509428d7b3dSmrg size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width; 510428d7b3dSmrg break; 511428d7b3dSmrg 512428d7b3dSmrg case DRI2BufferBackLeft: 513428d7b3dSmrg if (draw->type != DRAWABLE_PIXMAP) { 514428d7b3dSmrg if (dri2_window_get_front((WindowPtr)draw)) 515428d7b3dSmrg flags |= CREATE_SCANOUT; 516428d7b3dSmrg if (draw->width == sna->front->drawable.width && 517428d7b3dSmrg draw->height == sna->front->drawable.height && 518428d7b3dSmrg (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0) 519428d7b3dSmrg flags |= CREATE_SCANOUT; 520428d7b3dSmrg } 521428d7b3dSmrg case DRI2BufferBackRight: 522428d7b3dSmrg case DRI2BufferFrontRight: 523428d7b3dSmrg case DRI2BufferFakeFrontLeft: 524428d7b3dSmrg case DRI2BufferFakeFrontRight: 525428d7b3dSmrg bpp = draw->bitsPerPixel; 526428d7b3dSmrg DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n", 527428d7b3dSmrg __FUNCTION__, 528428d7b3dSmrg draw->width, draw->height, 529428d7b3dSmrg flags & CREATE_SCANOUT)); 530428d7b3dSmrg 531428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 532428d7b3dSmrg draw->width, 533428d7b3dSmrg draw->height, 534428d7b3dSmrg draw->bitsPerPixel, 535428d7b3dSmrg color_tiling(sna, draw), 536428d7b3dSmrg flags); 537428d7b3dSmrg break; 538428d7b3dSmrg 539428d7b3dSmrg case DRI2BufferStencil: 540428d7b3dSmrg /* 541428d7b3dSmrg * The stencil buffer has quirky pitch requirements. From Vol 542428d7b3dSmrg * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 543428d7b3dSmrg * Pitch": 544428d7b3dSmrg * The pitch must be set to 2x the value computed based on 545428d7b3dSmrg * width, as the stencil buffer is stored with two rows 546428d7b3dSmrg * interleaved. 547428d7b3dSmrg * To accomplish this, we resort to the nasty hack of doubling 548428d7b3dSmrg * the drm region's cpp and halving its height. 549428d7b3dSmrg * 550428d7b3dSmrg * If we neglect to double the pitch, then 551428d7b3dSmrg * drm_intel_gem_bo_map_gtt() maps the memory incorrectly. 552428d7b3dSmrg * 553428d7b3dSmrg * The alignment for W-tiling is quite different to the 554428d7b3dSmrg * nominal no-tiling case, so we have to account for 555428d7b3dSmrg * the tiled access pattern explicitly. 556428d7b3dSmrg * 557428d7b3dSmrg * The stencil buffer is W tiled. However, we request from 558428d7b3dSmrg * the kernel a non-tiled buffer because the kernel does 559428d7b3dSmrg * not understand W tiling and the GTT is incapable of 560428d7b3dSmrg * W fencing. 561428d7b3dSmrg */ 562428d7b3dSmrg bpp = format ? format : draw->bitsPerPixel; 563428d7b3dSmrg bpp *= 2; 564428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 565428d7b3dSmrg ALIGN(draw->width, 64), 566428d7b3dSmrg ALIGN((draw->height + 1) / 2, 64), 567428d7b3dSmrg bpp, I915_TILING_NONE, flags); 568428d7b3dSmrg break; 569428d7b3dSmrg 570428d7b3dSmrg case DRI2BufferDepth: 571428d7b3dSmrg case DRI2BufferDepthStencil: 572428d7b3dSmrg case DRI2BufferHiz: 573428d7b3dSmrg case DRI2BufferAccum: 574428d7b3dSmrg bpp = format ? format : draw->bitsPerPixel, 575428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 576428d7b3dSmrg draw->width, draw->height, bpp, 577428d7b3dSmrg other_tiling(sna, draw), 578428d7b3dSmrg flags); 579428d7b3dSmrg break; 580428d7b3dSmrg 581428d7b3dSmrg default: 582428d7b3dSmrg return NULL; 583428d7b3dSmrg } 584428d7b3dSmrg if (bo == NULL) 585428d7b3dSmrg return NULL; 586428d7b3dSmrg 587428d7b3dSmrg buffer = calloc(1, sizeof *buffer + sizeof *private); 588428d7b3dSmrg if (buffer == NULL) 589428d7b3dSmrg goto err; 590428d7b3dSmrg 591428d7b3dSmrg private = get_private(buffer); 592428d7b3dSmrg buffer->attachment = attachment; 593428d7b3dSmrg buffer->pitch = bo->pitch; 594428d7b3dSmrg buffer->cpp = bpp / 8; 595428d7b3dSmrg buffer->driverPrivate = private; 596428d7b3dSmrg buffer->format = format; 597428d7b3dSmrg buffer->flags = 0; 598428d7b3dSmrg buffer->name = kgem_bo_flink(&sna->kgem, bo); 599428d7b3dSmrg private->refcnt = 1; 600428d7b3dSmrg private->bo = bo; 601428d7b3dSmrg private->pixmap = pixmap; 602428d7b3dSmrg private->size = size; 603428d7b3dSmrg 604428d7b3dSmrg if (buffer->name == 0) 605428d7b3dSmrg goto err; 606428d7b3dSmrg 607428d7b3dSmrg if (pixmap) { 608428d7b3dSmrg struct sna_pixmap *priv; 609428d7b3dSmrg 610428d7b3dSmrg assert(attachment == DRI2BufferFrontLeft); 611428d7b3dSmrg assert(sna_pixmap_get_buffer(pixmap) == NULL); 612428d7b3dSmrg 613428d7b3dSmrg sna_pixmap_set_buffer(pixmap, buffer); 614428d7b3dSmrg assert(sna_pixmap_get_buffer(pixmap) == buffer); 615428d7b3dSmrg pixmap->refcnt++; 616428d7b3dSmrg 617428d7b3dSmrg priv = sna_pixmap(pixmap); 618428d7b3dSmrg assert(priv->flush == false); 619428d7b3dSmrg assert((priv->pinned & PIN_DRI2) == 0); 620428d7b3dSmrg 621428d7b3dSmrg /* Don't allow this named buffer to be replaced */ 622428d7b3dSmrg priv->pinned |= PIN_DRI2; 623428d7b3dSmrg 624428d7b3dSmrg /* We need to submit any modifications to and reads from this 625428d7b3dSmrg * buffer before we send any reply to the Client. 626428d7b3dSmrg * 627428d7b3dSmrg * As we don't track which Client, we flush for all. 628428d7b3dSmrg */ 629428d7b3dSmrg DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, priv->gpu_bo->handle)); 630428d7b3dSmrg priv->gpu_bo->flush = true; 631428d7b3dSmrg if (priv->gpu_bo->exec) 632428d7b3dSmrg sna->kgem.flush = 1; 633428d7b3dSmrg 634428d7b3dSmrg priv->flush |= 1; 635428d7b3dSmrg if (draw->type == DRAWABLE_PIXMAP) { 636428d7b3dSmrg /* DRI2 renders directly into GLXPixmaps, treat as hostile */ 637428d7b3dSmrg kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 638428d7b3dSmrg sna_damage_all(&priv->gpu_damage, pixmap); 639428d7b3dSmrg priv->clear = false; 640428d7b3dSmrg priv->cpu = false; 641428d7b3dSmrg priv->flush |= 2; 642428d7b3dSmrg } 643428d7b3dSmrg 644428d7b3dSmrg sna_accel_watch_flush(sna, 1); 645428d7b3dSmrg } 646428d7b3dSmrg 647428d7b3dSmrg return buffer; 648428d7b3dSmrg 649428d7b3dSmrgerr: 650428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 651428d7b3dSmrg free(buffer); 652428d7b3dSmrg return NULL; 653428d7b3dSmrg} 654428d7b3dSmrg 655428d7b3dSmrgstatic void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer) 656428d7b3dSmrg{ 657428d7b3dSmrg struct sna_dri2_private *private = get_private(buffer); 658428d7b3dSmrg 659428d7b3dSmrg if (buffer == NULL) 660428d7b3dSmrg return; 661428d7b3dSmrg 662428d7b3dSmrg DBG(("%s: %p [handle=%d] -- refcnt=%d, pixmap=%ld\n", 663428d7b3dSmrg __FUNCTION__, buffer, private->bo->handle, private->refcnt, 664428d7b3dSmrg private->pixmap ? private->pixmap->drawable.serialNumber : 0)); 665428d7b3dSmrg assert(private->refcnt > 0); 666428d7b3dSmrg if (--private->refcnt) 667428d7b3dSmrg return; 668428d7b3dSmrg 669428d7b3dSmrg assert(private->bo); 670428d7b3dSmrg 671428d7b3dSmrg if (private->proxy) { 672428d7b3dSmrg DBG(("%s: destroying proxy\n", __FUNCTION__)); 673428d7b3dSmrg _sna_dri2_destroy_buffer(sna, private->proxy); 674428d7b3dSmrg private->pixmap = NULL; 675428d7b3dSmrg } 676428d7b3dSmrg 677428d7b3dSmrg if (private->pixmap) { 678428d7b3dSmrg PixmapPtr pixmap = private->pixmap; 679428d7b3dSmrg struct sna_pixmap *priv = sna_pixmap(pixmap); 680428d7b3dSmrg 681428d7b3dSmrg assert(sna_pixmap_get_buffer(pixmap) == buffer); 682428d7b3dSmrg assert(priv->gpu_bo == private->bo); 683428d7b3dSmrg assert(priv->gpu_bo->flush); 684428d7b3dSmrg assert(priv->pinned & PIN_DRI2); 685428d7b3dSmrg assert(priv->flush); 686428d7b3dSmrg 687428d7b3dSmrg /* Undo the DRI markings on this pixmap */ 688428d7b3dSmrg DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n", 689428d7b3dSmrg __FUNCTION__, 690428d7b3dSmrg pixmap->drawable.serialNumber, 691428d7b3dSmrg pixmap == sna->front)); 692428d7b3dSmrg 693428d7b3dSmrg list_del(&priv->flush_list); 694428d7b3dSmrg 695428d7b3dSmrg DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle)); 696428d7b3dSmrg priv->gpu_bo->flush = false; 697428d7b3dSmrg priv->pinned &= ~PIN_DRI2; 698428d7b3dSmrg 699428d7b3dSmrg priv->flush = false; 700428d7b3dSmrg sna_accel_watch_flush(sna, -1); 701428d7b3dSmrg 702428d7b3dSmrg sna_pixmap_set_buffer(pixmap, NULL); 703428d7b3dSmrg pixmap->drawable.pScreen->DestroyPixmap(pixmap); 704428d7b3dSmrg } 705428d7b3dSmrg assert(private->bo->flush == false); 706428d7b3dSmrg 707428d7b3dSmrg kgem_bo_destroy(&sna->kgem, private->bo); 708428d7b3dSmrg free(buffer); 709428d7b3dSmrg} 710428d7b3dSmrg 711428d7b3dSmrgstatic void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer) 712428d7b3dSmrg{ 713428d7b3dSmrg _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), buffer); 714428d7b3dSmrg} 715428d7b3dSmrg 716428d7b3dSmrgstatic DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer) 717428d7b3dSmrg{ 718428d7b3dSmrg get_private(buffer)->refcnt++; 719428d7b3dSmrg return buffer; 720428d7b3dSmrg} 721428d7b3dSmrg 722428d7b3dSmrgstatic inline void damage(PixmapPtr pixmap, struct sna_pixmap *priv, RegionPtr region) 723428d7b3dSmrg{ 724428d7b3dSmrg assert(priv->gpu_bo); 725428d7b3dSmrg if (DAMAGE_IS_ALL(priv->gpu_damage)) 726428d7b3dSmrg goto done; 727428d7b3dSmrg 728428d7b3dSmrg if (region == NULL) { 729428d7b3dSmrgdamage_all: 730428d7b3dSmrg priv->gpu_damage = _sna_damage_all(priv->gpu_damage, 731428d7b3dSmrg pixmap->drawable.width, 732428d7b3dSmrg pixmap->drawable.height); 733428d7b3dSmrg sna_damage_destroy(&priv->cpu_damage); 734428d7b3dSmrg list_del(&priv->flush_list); 735428d7b3dSmrg } else { 736428d7b3dSmrg sna_damage_subtract(&priv->cpu_damage, region); 737428d7b3dSmrg if (priv->cpu_damage == NULL) 738428d7b3dSmrg goto damage_all; 739428d7b3dSmrg sna_damage_add(&priv->gpu_damage, region); 740428d7b3dSmrg } 741428d7b3dSmrgdone: 742428d7b3dSmrg priv->cpu = false; 743428d7b3dSmrg priv->clear = false; 744428d7b3dSmrg} 745428d7b3dSmrg 746428d7b3dSmrgstatic void set_bo(PixmapPtr pixmap, struct kgem_bo *bo) 747428d7b3dSmrg{ 748428d7b3dSmrg struct sna *sna = to_sna_from_pixmap(pixmap); 749428d7b3dSmrg struct sna_pixmap *priv = sna_pixmap(pixmap); 750428d7b3dSmrg RegionRec region; 751428d7b3dSmrg 752428d7b3dSmrg DBG(("%s: pixmap=%ld, handle=%d\n", 753428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber, bo->handle)); 754428d7b3dSmrg 755428d7b3dSmrg assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch); 756428d7b3dSmrg assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo)); 757428d7b3dSmrg assert(bo->proxy == NULL); 758428d7b3dSmrg assert(priv->pinned & PIN_DRI2); 759428d7b3dSmrg assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0); 760428d7b3dSmrg assert(priv->flush); 761428d7b3dSmrg 762428d7b3dSmrg /* Post damage on the new front buffer so that listeners, such 763428d7b3dSmrg * as DisplayLink know take a copy and shove it over the USB, 764428d7b3dSmrg * also for software cursors and the like. 765428d7b3dSmrg */ 766428d7b3dSmrg region.extents.x1 = region.extents.y1 = 0; 767428d7b3dSmrg region.extents.x2 = pixmap->drawable.width; 768428d7b3dSmrg region.extents.y2 = pixmap->drawable.height; 769428d7b3dSmrg region.data = NULL; 770428d7b3dSmrg DamageRegionAppend(&pixmap->drawable, ®ion); 771428d7b3dSmrg 772428d7b3dSmrg damage(pixmap, priv, NULL); 773428d7b3dSmrg 774428d7b3dSmrg assert(bo->refcnt); 775428d7b3dSmrg if (priv->move_to_gpu) 776428d7b3dSmrg priv->move_to_gpu(sna, priv, 0); 777428d7b3dSmrg if (priv->gpu_bo != bo) { 778428d7b3dSmrg DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle)); 779428d7b3dSmrg priv->gpu_bo->flush = false; 780428d7b3dSmrg if (priv->cow) 781428d7b3dSmrg sna_pixmap_undo_cow(sna, priv, 0); 782428d7b3dSmrg if (priv->gpu_bo) { 783428d7b3dSmrg sna_pixmap_unmap(pixmap, priv); 784428d7b3dSmrg kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 785428d7b3dSmrg } 786428d7b3dSmrg DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle)); 787428d7b3dSmrg bo->flush = true; 788428d7b3dSmrg if (bo->exec) 789428d7b3dSmrg sna->kgem.flush = 1; 790428d7b3dSmrg priv->gpu_bo = ref(bo); 791428d7b3dSmrg } 792428d7b3dSmrg if (bo->domain != DOMAIN_GPU) 793428d7b3dSmrg bo->domain = DOMAIN_NONE; 794428d7b3dSmrg assert(bo->flush); 795428d7b3dSmrg 796428d7b3dSmrg DamageRegionProcessPending(&pixmap->drawable); 797428d7b3dSmrg} 798428d7b3dSmrg 799428d7b3dSmrgstatic void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync) 800428d7b3dSmrg{ 801428d7b3dSmrg struct drm_i915_gem_busy busy; 802428d7b3dSmrg int mode; 803428d7b3dSmrg 804428d7b3dSmrg if (sna->kgem.gen < 060) 805428d7b3dSmrg return; 806428d7b3dSmrg 807428d7b3dSmrg if (sync) { 808428d7b3dSmrg DBG(("%s: sync, force %s ring\n", __FUNCTION__, 809428d7b3dSmrg sna->kgem.gen >= 070 ? "BLT" : "RENDER")); 810428d7b3dSmrg kgem_set_mode(&sna->kgem, 811428d7b3dSmrg sna->kgem.gen >= 070 ? KGEM_BLT : KGEM_RENDER, 812428d7b3dSmrg dst); 813428d7b3dSmrg return; 814428d7b3dSmrg } 815428d7b3dSmrg 816428d7b3dSmrg if (DBG_FORCE_COPY != -1) { 817428d7b3dSmrg DBG(("%s: forcing %d\n", __FUNCTION__, DBG_FORCE_COPY)); 818428d7b3dSmrg kgem_set_mode(&sna->kgem, DBG_FORCE_COPY, dst); 819428d7b3dSmrg return; 820428d7b3dSmrg } 821428d7b3dSmrg 822428d7b3dSmrg if (sna->kgem.mode != KGEM_NONE) { 823428d7b3dSmrg DBG(("%s: busy, not switching\n", __FUNCTION__)); 824428d7b3dSmrg return; 825428d7b3dSmrg } 826428d7b3dSmrg 827428d7b3dSmrg VG_CLEAR(busy); 828428d7b3dSmrg busy.handle = src->handle; 829428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy)) 830428d7b3dSmrg return; 831428d7b3dSmrg 832428d7b3dSmrg DBG(("%s: src handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy)); 833428d7b3dSmrg if (busy.busy == 0) { 834428d7b3dSmrg __kgem_bo_clear_busy(src); 835428d7b3dSmrg 836428d7b3dSmrg busy.handle = dst->handle; 837428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy)) 838428d7b3dSmrg return; 839428d7b3dSmrg 840428d7b3dSmrg DBG(("%s: dst handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy)); 841428d7b3dSmrg if (busy.busy == 0) { 842428d7b3dSmrg __kgem_bo_clear_busy(dst); 843428d7b3dSmrg DBG(("%s: src/dst is idle, using defaults\n", __FUNCTION__)); 844428d7b3dSmrg return; 845428d7b3dSmrg } 846428d7b3dSmrg } 847428d7b3dSmrg 848428d7b3dSmrg /* Sandybridge introduced a separate ring which it uses to 849428d7b3dSmrg * perform blits. Switching rendering between rings incurs 850428d7b3dSmrg * a stall as we wait upon the old ring to finish and 851428d7b3dSmrg * flush its render cache before we can proceed on with 852428d7b3dSmrg * the operation on the new ring. 853428d7b3dSmrg * 854428d7b3dSmrg * As this buffer, we presume, has just been written to by 855428d7b3dSmrg * the DRI client using the RENDER ring, we want to perform 856428d7b3dSmrg * our operation on the same ring, and ideally on the same 857428d7b3dSmrg * ring as we will flip from (which should be the RENDER ring 858428d7b3dSmrg * as well). 859428d7b3dSmrg * 860428d7b3dSmrg * The ultimate question is whether preserving the ring outweighs 861428d7b3dSmrg * the cost of the query. 862428d7b3dSmrg */ 863428d7b3dSmrg mode = KGEM_RENDER; 864428d7b3dSmrg if (busy.busy & (0xfffe << 16)) 865428d7b3dSmrg mode = KGEM_BLT; 866428d7b3dSmrg kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode); 867428d7b3dSmrg _kgem_set_mode(&sna->kgem, mode); 868428d7b3dSmrg} 869428d7b3dSmrg 870428d7b3dSmrgstatic bool is_front(int attachment) 871428d7b3dSmrg{ 872428d7b3dSmrg return attachment == DRI2BufferFrontLeft; 873428d7b3dSmrg} 874428d7b3dSmrg 875428d7b3dSmrgstatic struct kgem_bo * 876428d7b3dSmrg__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region, 877428d7b3dSmrg DRI2BufferPtr src, DRI2BufferPtr dst, 878428d7b3dSmrg bool sync) 879428d7b3dSmrg{ 880428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(draw); 881428d7b3dSmrg DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable; 882428d7b3dSmrg struct sna_dri2_private *src_priv = get_private(src); 883428d7b3dSmrg struct sna_dri2_private *dst_priv = get_private(dst); 884428d7b3dSmrg pixman_region16_t clip; 885428d7b3dSmrg struct kgem_bo *bo = NULL; 886428d7b3dSmrg struct kgem_bo *src_bo; 887428d7b3dSmrg struct kgem_bo *dst_bo; 888428d7b3dSmrg const BoxRec *boxes; 889428d7b3dSmrg int16_t dx, dy, sx, sy; 890428d7b3dSmrg unsigned flags; 891428d7b3dSmrg int n; 892428d7b3dSmrg 893428d7b3dSmrg /* To hide a stale DRI2Buffer, one may choose to substitute 894428d7b3dSmrg * pixmap->gpu_bo instead of dst/src->bo, however you then run 895428d7b3dSmrg * the risk of copying around invalid data. So either you may not 896428d7b3dSmrg * see the results of the copy, or you may see the wrong pixels. 897428d7b3dSmrg * Either way you eventually lose. 898428d7b3dSmrg * 899428d7b3dSmrg * We also have to be careful in case that the stale buffers are 900428d7b3dSmrg * now attached to invalid (non-DRI) pixmaps. 901428d7b3dSmrg */ 902428d7b3dSmrg 903428d7b3dSmrg assert(is_front(dst->attachment) || is_front(src->attachment)); 904428d7b3dSmrg assert(dst->attachment != src->attachment); 905428d7b3dSmrg 906428d7b3dSmrg clip.extents.x1 = draw->x; 907428d7b3dSmrg clip.extents.y1 = draw->y; 908428d7b3dSmrg clip.extents.x2 = draw->x + draw->width; 909428d7b3dSmrg clip.extents.y2 = draw->y + draw->height; 910428d7b3dSmrg clip.data = NULL; 911428d7b3dSmrg 912428d7b3dSmrg if (region) { 913428d7b3dSmrg pixman_region_translate(region, draw->x, draw->y); 914428d7b3dSmrg pixman_region_intersect(&clip, &clip, region); 915428d7b3dSmrg region = &clip; 916428d7b3dSmrg } 917428d7b3dSmrg 918428d7b3dSmrg if (clip.extents.x1 >= clip.extents.x2 || 919428d7b3dSmrg clip.extents.y1 >= clip.extents.y2) { 920428d7b3dSmrg DBG(("%s: all clipped\n", __FUNCTION__)); 921428d7b3dSmrg return NULL; 922428d7b3dSmrg } 923428d7b3dSmrg 924428d7b3dSmrg sx = sy = dx = dy = 0; 925428d7b3dSmrg if (is_front(dst->attachment)) { 926428d7b3dSmrg sx = -draw->x; 927428d7b3dSmrg sy = -draw->y; 928428d7b3dSmrg } else { 929428d7b3dSmrg dx = -draw->x; 930428d7b3dSmrg dy = -draw->y; 931428d7b3dSmrg } 932428d7b3dSmrg if (draw->type == DRAWABLE_WINDOW) { 933428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 934428d7b3dSmrg int16_t tx, ty; 935428d7b3dSmrg 936428d7b3dSmrg if (is_clipped(&win->clipList, draw)) { 937428d7b3dSmrg DBG(("%s: draw=(%d, %d), delta=(%d, %d), draw=(%d, %d),(%d, %d), clip.extents=(%d, %d), (%d, %d)\n", 938428d7b3dSmrg __FUNCTION__, draw->x, draw->y, 939428d7b3dSmrg get_drawable_dx(draw), get_drawable_dy(draw), 940428d7b3dSmrg clip.extents.x1, clip.extents.y1, 941428d7b3dSmrg clip.extents.x2, clip.extents.y2, 942428d7b3dSmrg win->clipList.extents.x1, win->clipList.extents.y1, 943428d7b3dSmrg win->clipList.extents.x2, win->clipList.extents.y2)); 944428d7b3dSmrg 945428d7b3dSmrg assert(region == NULL || region == &clip); 946428d7b3dSmrg pixman_region_intersect(&clip, &win->clipList, &clip); 947428d7b3dSmrg if (!pixman_region_not_empty(&clip)) { 948428d7b3dSmrg DBG(("%s: all clipped\n", __FUNCTION__)); 949428d7b3dSmrg return NULL; 950428d7b3dSmrg } 951428d7b3dSmrg 952428d7b3dSmrg region = &clip; 953428d7b3dSmrg } 954428d7b3dSmrg 955428d7b3dSmrg if (get_drawable_deltas(draw, pixmap, &tx, &ty)) { 956428d7b3dSmrg if (is_front(dst->attachment)) { 957428d7b3dSmrg pixman_region_translate(region ?: &clip, tx, ty); 958428d7b3dSmrg sx -= tx; 959428d7b3dSmrg sy -= ty; 960428d7b3dSmrg } else { 961428d7b3dSmrg sx += tx; 962428d7b3dSmrg sy += ty; 963428d7b3dSmrg } 964428d7b3dSmrg } 965428d7b3dSmrg } else 966428d7b3dSmrg sync = false; 967428d7b3dSmrg 968428d7b3dSmrg scratch.x = scratch.y = 0; 969428d7b3dSmrg scratch.width = scratch.height = 0; 970428d7b3dSmrg scratch.depth = draw->depth; 971428d7b3dSmrg scratch.bitsPerPixel = draw->bitsPerPixel; 972428d7b3dSmrg 973428d7b3dSmrg src_bo = src_priv->bo; 974428d7b3dSmrg assert(src_bo->refcnt); 975428d7b3dSmrg if (is_front(src->attachment)) { 976428d7b3dSmrg struct sna_pixmap *priv; 977428d7b3dSmrg 978428d7b3dSmrg priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 979428d7b3dSmrg if (priv) 980428d7b3dSmrg src_bo = priv->gpu_bo; 981428d7b3dSmrg DBG(("%s: updated FrontLeft src_bo from handle=%d to handle=%d\n", 982428d7b3dSmrg __FUNCTION__, src_priv->bo->handle, src_bo->handle)); 983428d7b3dSmrg assert(src_bo->refcnt); 984428d7b3dSmrg } else { 985428d7b3dSmrg RegionRec source; 986428d7b3dSmrg 987428d7b3dSmrg scratch.width = src_priv->size & 0xffff; 988428d7b3dSmrg scratch.height = src_priv->size >> 16; 989428d7b3dSmrg src_draw = &scratch; 990428d7b3dSmrg 991428d7b3dSmrg DBG(("%s: source size %dx%d, region size %dx%d\n", 992428d7b3dSmrg __FUNCTION__, 993428d7b3dSmrg scratch.width, scratch.height, 994428d7b3dSmrg clip.extents.x2 - clip.extents.x1, 995428d7b3dSmrg clip.extents.y2 - clip.extents.y1)); 996428d7b3dSmrg 997428d7b3dSmrg source.extents.x1 = -sx; 998428d7b3dSmrg source.extents.y1 = -sy; 999428d7b3dSmrg source.extents.x2 = source.extents.x1 + scratch.width; 1000428d7b3dSmrg source.extents.y2 = source.extents.y1 + scratch.height; 1001428d7b3dSmrg source.data = NULL; 1002428d7b3dSmrg 1003428d7b3dSmrg assert(region == NULL || region == &clip); 1004428d7b3dSmrg pixman_region_intersect(&clip, &clip, &source); 1005428d7b3dSmrg 1006428d7b3dSmrg } 1007428d7b3dSmrg 1008428d7b3dSmrg dst_bo = dst_priv->bo; 1009428d7b3dSmrg assert(dst_bo->refcnt); 1010428d7b3dSmrg if (is_front(dst->attachment)) { 1011428d7b3dSmrg struct sna_pixmap *priv; 1012428d7b3dSmrg struct list shadow; 1013428d7b3dSmrg 1014428d7b3dSmrg /* Preserve the CRTC shadow overrides */ 1015428d7b3dSmrg sna_shadow_steal_crtcs(sna, &shadow); 1016428d7b3dSmrg 1017428d7b3dSmrg flags = MOVE_WRITE | __MOVE_FORCE; 1018428d7b3dSmrg if (clip.data) 1019428d7b3dSmrg flags |= MOVE_READ; 1020428d7b3dSmrg 1021428d7b3dSmrg assert(region == NULL || region == &clip); 1022428d7b3dSmrg priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags); 1023428d7b3dSmrg if (priv) { 1024428d7b3dSmrg damage(pixmap, priv, region); 1025428d7b3dSmrg dst_bo = priv->gpu_bo; 1026428d7b3dSmrg } 1027428d7b3dSmrg DBG(("%s: updated FrontLeft dst_bo from handle=%d to handle=%d\n", 1028428d7b3dSmrg __FUNCTION__, dst_priv->bo->handle, dst_bo->handle)); 1029428d7b3dSmrg assert(dst_bo->refcnt); 1030428d7b3dSmrg 1031428d7b3dSmrg sna_shadow_unsteal_crtcs(sna, &shadow); 1032428d7b3dSmrg } else { 1033428d7b3dSmrg RegionRec target; 1034428d7b3dSmrg 1035428d7b3dSmrg scratch.width = dst_priv->size & 0xffff; 1036428d7b3dSmrg scratch.height = dst_priv->size >> 16; 1037428d7b3dSmrg dst_draw = &scratch; 1038428d7b3dSmrg 1039428d7b3dSmrg DBG(("%s: target size %dx%d, region size %dx%d\n", 1040428d7b3dSmrg __FUNCTION__, 1041428d7b3dSmrg scratch.width, scratch.height, 1042428d7b3dSmrg clip.extents.x2 - clip.extents.x1, 1043428d7b3dSmrg clip.extents.y2 - clip.extents.y1)); 1044428d7b3dSmrg 1045428d7b3dSmrg target.extents.x1 = -dx; 1046428d7b3dSmrg target.extents.y1 = -dy; 1047428d7b3dSmrg target.extents.x2 = target.extents.x1 + scratch.width; 1048428d7b3dSmrg target.extents.y2 = target.extents.y1 + scratch.height; 1049428d7b3dSmrg target.data = NULL; 1050428d7b3dSmrg 1051428d7b3dSmrg assert(region == NULL || region == &clip); 1052428d7b3dSmrg pixman_region_intersect(&clip, &clip, &target); 1053428d7b3dSmrg 1054428d7b3dSmrg sync = false; 1055428d7b3dSmrg } 1056428d7b3dSmrg 1057428d7b3dSmrg if (!wedged(sna)) { 1058428d7b3dSmrg xf86CrtcPtr crtc; 1059428d7b3dSmrg 1060428d7b3dSmrg crtc = NULL; 1061428d7b3dSmrg if (sync && sna_pixmap_is_scanout(sna, pixmap)) 1062428d7b3dSmrg crtc = sna_covering_crtc(sna, &clip.extents, NULL); 1063428d7b3dSmrg sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL); 1064428d7b3dSmrg 1065428d7b3dSmrg sync = (crtc != NULL&& 1066428d7b3dSmrg sna_wait_for_scanline(sna, pixmap, crtc, 1067428d7b3dSmrg &clip.extents)); 1068428d7b3dSmrg } 1069428d7b3dSmrg 1070428d7b3dSmrg if (region) { 1071428d7b3dSmrg boxes = region_rects(region); 1072428d7b3dSmrg n = region_num_rects(region); 1073428d7b3dSmrg assert(n); 1074428d7b3dSmrg } else { 1075428d7b3dSmrg region = &clip; 1076428d7b3dSmrg boxes = &clip.extents; 1077428d7b3dSmrg n = 1; 1078428d7b3dSmrg } 1079428d7b3dSmrg DamageRegionAppend(&pixmap->drawable, region); 1080428d7b3dSmrg 1081428d7b3dSmrg 1082428d7b3dSmrg DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n", 1083428d7b3dSmrg __FUNCTION__, 1084428d7b3dSmrg boxes[0].x1, boxes[0].y1, 1085428d7b3dSmrg boxes[0].x2, boxes[0].y2, 1086428d7b3dSmrg n, sx, sy, dx, dy)); 1087428d7b3dSmrg 1088428d7b3dSmrg flags = COPY_LAST; 1089428d7b3dSmrg if (sync) 1090428d7b3dSmrg flags |= COPY_SYNC; 1091428d7b3dSmrg if (!sna->render.copy_boxes(sna, GXcopy, 1092428d7b3dSmrg src_draw, src_bo, sx, sy, 1093428d7b3dSmrg dst_draw, dst_bo, dx, dy, 1094428d7b3dSmrg boxes, n, flags)) 1095428d7b3dSmrg memcpy_copy_boxes(sna, GXcopy, 1096428d7b3dSmrg src_draw, src_bo, sx, sy, 1097428d7b3dSmrg dst_draw, dst_bo, dx, dy, 1098428d7b3dSmrg boxes, n, flags); 1099428d7b3dSmrg 1100428d7b3dSmrg DBG(("%s: flushing? %d\n", __FUNCTION__, sync)); 1101428d7b3dSmrg if (sync) { /* STAT! */ 1102428d7b3dSmrg struct kgem_request *rq = sna->kgem.next_request; 1103428d7b3dSmrg kgem_submit(&sna->kgem); 1104428d7b3dSmrg if (rq->bo) { 1105428d7b3dSmrg bo = ref(rq->bo); 1106428d7b3dSmrg DBG(("%s: recording sync fence handle=%d\n", __FUNCTION__, bo->handle)); 1107428d7b3dSmrg } 1108428d7b3dSmrg } 1109428d7b3dSmrg 1110428d7b3dSmrg DamageRegionProcessPending(&pixmap->drawable); 1111428d7b3dSmrg 1112428d7b3dSmrg if (clip.data) 1113428d7b3dSmrg pixman_region_fini(&clip); 1114428d7b3dSmrg 1115428d7b3dSmrg return bo; 1116428d7b3dSmrg} 1117428d7b3dSmrg 1118428d7b3dSmrgstatic void 1119428d7b3dSmrgsna_dri2_copy_region(DrawablePtr draw, 1120428d7b3dSmrg RegionPtr region, 1121428d7b3dSmrg DRI2BufferPtr dst, 1122428d7b3dSmrg DRI2BufferPtr src) 1123428d7b3dSmrg{ 1124428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(draw); 1125428d7b3dSmrg struct sna *sna = to_sna_from_pixmap(pixmap); 1126428d7b3dSmrg 1127428d7b3dSmrg DBG(("%s: pixmap=%ld, src=%u (refs=%d/%d, flush=%d, attach=%d) , dst=%u (refs=%d/%d, flush=%d, attach=%d)\n", 1128428d7b3dSmrg __FUNCTION__, 1129428d7b3dSmrg pixmap->drawable.serialNumber, 1130428d7b3dSmrg get_private(src)->bo->handle, 1131428d7b3dSmrg get_private(src)->refcnt, 1132428d7b3dSmrg get_private(src)->bo->refcnt, 1133428d7b3dSmrg get_private(src)->bo->flush, 1134428d7b3dSmrg src->attachment, 1135428d7b3dSmrg get_private(dst)->bo->handle, 1136428d7b3dSmrg get_private(dst)->refcnt, 1137428d7b3dSmrg get_private(dst)->bo->refcnt, 1138428d7b3dSmrg get_private(dst)->bo->flush, 1139428d7b3dSmrg dst->attachment)); 1140428d7b3dSmrg 1141428d7b3dSmrg assert(src != dst); 1142428d7b3dSmrg 1143428d7b3dSmrg assert(get_private(src)->refcnt); 1144428d7b3dSmrg assert(get_private(dst)->refcnt); 1145428d7b3dSmrg 1146428d7b3dSmrg assert(get_private(src)->bo->refcnt); 1147428d7b3dSmrg assert(get_private(dst)->bo->refcnt); 1148428d7b3dSmrg 1149428d7b3dSmrg DBG(("%s: region (%d, %d), (%d, %d) x %d\n", 1150428d7b3dSmrg __FUNCTION__, 1151428d7b3dSmrg region->extents.x1, region->extents.y1, 1152428d7b3dSmrg region->extents.x2, region->extents.y2, 1153428d7b3dSmrg region_num_rects(region))); 1154428d7b3dSmrg 1155428d7b3dSmrg __sna_dri2_copy_region(sna, draw, region, src, dst, false); 1156428d7b3dSmrg} 1157428d7b3dSmrg 1158428d7b3dSmrginline static uint32_t pipe_select(int pipe) 1159428d7b3dSmrg{ 1160428d7b3dSmrg /* The third pipe was introduced with IvyBridge long after 1161428d7b3dSmrg * multiple pipe support was added to the kernel, hence 1162428d7b3dSmrg * we can safely ignore the capability check - if we have more 1163428d7b3dSmrg * than two pipes, we can assume that they are fully supported. 1164428d7b3dSmrg */ 1165428d7b3dSmrg if (pipe > 1) 1166428d7b3dSmrg return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 1167428d7b3dSmrg else if (pipe > 0) 1168428d7b3dSmrg return DRM_VBLANK_SECONDARY; 1169428d7b3dSmrg else 1170428d7b3dSmrg return 0; 1171428d7b3dSmrg} 1172428d7b3dSmrg 1173428d7b3dSmrgstatic inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe) 1174428d7b3dSmrg{ 1175428d7b3dSmrg DBG(("%s(pipe=%d, waiting until seq=%u%s)\n", 1176428d7b3dSmrg __FUNCTION__, pipe, vbl->request.sequence, 1177428d7b3dSmrg vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : "")); 1178428d7b3dSmrg assert(pipe != -1); 1179428d7b3dSmrg 1180428d7b3dSmrg vbl->request.type |= pipe_select(pipe); 1181428d7b3dSmrg return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl); 1182428d7b3dSmrg} 1183428d7b3dSmrg 1184428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 1185428d7b3dSmrg 1186428d7b3dSmrgstatic void dri2_window_attach(WindowPtr win, struct dri2_window *priv) 1187428d7b3dSmrg{ 1188428d7b3dSmrg assert(win->drawable.type == DRAWABLE_WINDOW); 1189428d7b3dSmrg assert(dri2_window(win) == NULL); 1190428d7b3dSmrg ((void **)__get_private(win, sna_window_key))[1] = priv; 1191428d7b3dSmrg assert(dri2_window(win) == priv); 1192428d7b3dSmrg} 1193428d7b3dSmrg 1194428d7b3dSmrgstatic uint64_t 1195428d7b3dSmrgdraw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc) 1196428d7b3dSmrg{ 1197428d7b3dSmrg struct dri2_window *priv; 1198428d7b3dSmrg 1199428d7b3dSmrg if (draw->type != DRAWABLE_WINDOW) 1200428d7b3dSmrg return msc; 1201428d7b3dSmrg 1202428d7b3dSmrg priv = dri2_window((WindowPtr)draw); 1203428d7b3dSmrg if (priv == NULL) { 1204428d7b3dSmrg priv = malloc(sizeof(*priv)); 1205428d7b3dSmrg if (priv != NULL) { 1206428d7b3dSmrg priv->front = NULL; 1207428d7b3dSmrg priv->crtc = crtc; 1208428d7b3dSmrg priv->msc_delta = 0; 1209428d7b3dSmrg priv->chain = NULL; 1210428d7b3dSmrg dri2_window_attach((WindowPtr)draw, priv); 1211428d7b3dSmrg } 1212428d7b3dSmrg } else { 1213428d7b3dSmrg if (priv->crtc != crtc) { 1214428d7b3dSmrg const struct ust_msc *last = sna_crtc_last_swap(priv->crtc); 1215428d7b3dSmrg const struct ust_msc *this = sna_crtc_last_swap(crtc); 1216428d7b3dSmrg DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n", 1217428d7b3dSmrg __FUNCTION__, 1218428d7b3dSmrg sna_crtc_to_pipe(priv->crtc), (long long)last->msc, 1219428d7b3dSmrg sna_crtc_to_pipe(crtc), (long long)this->msc, 1220428d7b3dSmrg (long long)(priv->msc_delta + this->msc - last->msc))); 1221428d7b3dSmrg priv->msc_delta += this->msc - last->msc; 1222428d7b3dSmrg priv->crtc = crtc; 1223428d7b3dSmrg } 1224428d7b3dSmrg msc -= priv->msc_delta; 1225428d7b3dSmrg } 1226428d7b3dSmrg return msc; 1227428d7b3dSmrg} 1228428d7b3dSmrg 1229428d7b3dSmrgstatic uint32_t 1230428d7b3dSmrgdraw_target_seq(DrawablePtr draw, uint64_t msc) 1231428d7b3dSmrg{ 1232428d7b3dSmrg struct dri2_window *priv = dri2_window((WindowPtr)draw); 1233428d7b3dSmrg if (priv == NULL) 1234428d7b3dSmrg return msc; 1235428d7b3dSmrg DBG(("%s: converting target_msc=%llu to seq %u\n", 1236428d7b3dSmrg __FUNCTION__, (long long)msc, (unsigned)(msc + priv->msc_delta))); 1237428d7b3dSmrg return msc + priv->msc_delta; 1238428d7b3dSmrg} 1239428d7b3dSmrg 1240428d7b3dSmrgstatic xf86CrtcPtr 1241428d7b3dSmrgsna_dri2_get_crtc(DrawablePtr draw) 1242428d7b3dSmrg{ 1243428d7b3dSmrg if (draw->type == DRAWABLE_PIXMAP) 1244428d7b3dSmrg return NULL; 1245428d7b3dSmrg 1246428d7b3dSmrg /* Make sure the CRTC is valid and this is the real front buffer */ 1247428d7b3dSmrg return sna_covering_crtc(to_sna_from_drawable(draw), 1248428d7b3dSmrg &((WindowPtr)draw)->clipList.extents, 1249428d7b3dSmrg NULL); 1250428d7b3dSmrg} 1251428d7b3dSmrg 1252428d7b3dSmrgstatic void 1253428d7b3dSmrgsna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info) 1254428d7b3dSmrg{ 1255428d7b3dSmrg struct dri2_window *priv; 1256428d7b3dSmrg struct sna_dri2_event *chain; 1257428d7b3dSmrg 1258428d7b3dSmrg assert(win->drawable.type == DRAWABLE_WINDOW); 1259428d7b3dSmrg DBG(("%s: remove[%p] from window %ld, active? %d\n", 1260428d7b3dSmrg __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL)); 1261428d7b3dSmrg 1262428d7b3dSmrg priv = dri2_window(win); 1263428d7b3dSmrg assert(priv); 1264428d7b3dSmrg assert(priv->chain != NULL); 1265428d7b3dSmrg 1266428d7b3dSmrg if (priv->chain == info) { 1267428d7b3dSmrg priv->chain = info->chain; 1268428d7b3dSmrg return; 1269428d7b3dSmrg } 1270428d7b3dSmrg 1271428d7b3dSmrg chain = priv->chain; 1272428d7b3dSmrg while (chain->chain != info) 1273428d7b3dSmrg chain = chain->chain; 1274428d7b3dSmrg assert(chain != info); 1275428d7b3dSmrg assert(info->chain != chain); 1276428d7b3dSmrg chain->chain = info->chain; 1277428d7b3dSmrg} 1278428d7b3dSmrg 1279428d7b3dSmrgstatic void 1280428d7b3dSmrgsna_dri2_event_free(struct sna_dri2_event *info) 1281428d7b3dSmrg{ 1282428d7b3dSmrg DrawablePtr draw = info->draw; 1283428d7b3dSmrg 1284428d7b3dSmrg DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL)); 1285428d7b3dSmrg if (draw && draw->type == DRAWABLE_WINDOW) 1286428d7b3dSmrg sna_dri2_remove_event((WindowPtr)draw, info); 1287428d7b3dSmrg 1288428d7b3dSmrg _sna_dri2_destroy_buffer(info->sna, info->front); 1289428d7b3dSmrg _sna_dri2_destroy_buffer(info->sna, info->back); 1290428d7b3dSmrg 1291428d7b3dSmrg while (!list_is_empty(&info->cache)) { 1292428d7b3dSmrg struct dri_bo *c; 1293428d7b3dSmrg 1294428d7b3dSmrg c = list_first_entry(&info->cache, struct dri_bo, link); 1295428d7b3dSmrg list_del(&c->link); 1296428d7b3dSmrg 1297428d7b3dSmrg DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0)); 1298428d7b3dSmrg if (c->bo) 1299428d7b3dSmrg kgem_bo_destroy(&info->sna->kgem, c->bo); 1300428d7b3dSmrg 1301428d7b3dSmrg free(c); 1302428d7b3dSmrg } 1303428d7b3dSmrg 1304428d7b3dSmrg if (info->bo) { 1305428d7b3dSmrg DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle)); 1306428d7b3dSmrg kgem_bo_destroy(&info->sna->kgem, info->bo); 1307428d7b3dSmrg } 1308428d7b3dSmrg 1309428d7b3dSmrg _list_del(&info->link); 1310428d7b3dSmrg free(info); 1311428d7b3dSmrg} 1312428d7b3dSmrg 1313428d7b3dSmrgstatic void 1314428d7b3dSmrgsna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data) 1315428d7b3dSmrg{ 1316428d7b3dSmrg NewClientInfoRec *clientinfo = data; 1317428d7b3dSmrg ClientPtr client = clientinfo->client; 1318428d7b3dSmrg struct sna_client *priv = sna_client(client); 1319428d7b3dSmrg struct sna *sna = closure; 1320428d7b3dSmrg 1321428d7b3dSmrg if (priv->events.next == NULL) 1322428d7b3dSmrg return; 1323428d7b3dSmrg 1324428d7b3dSmrg if (client->clientState != ClientStateGone) 1325428d7b3dSmrg return; 1326428d7b3dSmrg 1327428d7b3dSmrg DBG(("%s(active?=%d)\n", __FUNCTION__, 1328428d7b3dSmrg !list_is_empty(&priv->events))); 1329428d7b3dSmrg 1330428d7b3dSmrg while (!list_is_empty(&priv->events)) { 1331428d7b3dSmrg struct sna_dri2_event *event; 1332428d7b3dSmrg 1333428d7b3dSmrg event = list_first_entry(&priv->events, struct sna_dri2_event, link); 1334428d7b3dSmrg assert(event->client == client); 1335428d7b3dSmrg 1336428d7b3dSmrg if (event->queued) { 1337428d7b3dSmrg if (event->draw) 1338428d7b3dSmrg sna_dri2_remove_event((WindowPtr)event->draw, 1339428d7b3dSmrg event); 1340428d7b3dSmrg event->client = NULL; 1341428d7b3dSmrg event->draw = NULL; 1342428d7b3dSmrg list_del(&event->link); 1343428d7b3dSmrg } else 1344428d7b3dSmrg sna_dri2_event_free(event); 1345428d7b3dSmrg } 1346428d7b3dSmrg 1347428d7b3dSmrg if (--sna->dri2.client_count == 0) 1348428d7b3dSmrg DeleteCallback(&ClientStateCallback, sna_dri2_client_gone, sna); 1349428d7b3dSmrg} 1350428d7b3dSmrg 1351428d7b3dSmrgstatic bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, ClientPtr client) 1352428d7b3dSmrg{ 1353428d7b3dSmrg struct sna_client *priv = sna_client(client); 1354428d7b3dSmrg 1355428d7b3dSmrg if (priv->events.next == NULL) { 1356428d7b3dSmrg if (sna->dri2.client_count++ == 0 && 1357428d7b3dSmrg !AddCallback(&ClientStateCallback, sna_dri2_client_gone, sna)) 1358428d7b3dSmrg return false; 1359428d7b3dSmrg 1360428d7b3dSmrg list_init(&priv->events); 1361428d7b3dSmrg } 1362428d7b3dSmrg 1363428d7b3dSmrg list_add(&info->link, &priv->events); 1364428d7b3dSmrg info->client = client; 1365428d7b3dSmrg return true; 1366428d7b3dSmrg} 1367428d7b3dSmrg 1368428d7b3dSmrgstatic struct sna_dri2_event * 1369428d7b3dSmrgsna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client) 1370428d7b3dSmrg{ 1371428d7b3dSmrg struct dri2_window *priv; 1372428d7b3dSmrg struct sna_dri2_event *info, *chain; 1373428d7b3dSmrg 1374428d7b3dSmrg assert(draw->type == DRAWABLE_WINDOW); 1375428d7b3dSmrg DBG(("%s: adding event to window %ld)\n", 1376428d7b3dSmrg __FUNCTION__, (long)draw->id)); 1377428d7b3dSmrg 1378428d7b3dSmrg priv = dri2_window((WindowPtr)draw); 1379428d7b3dSmrg if (priv == NULL) 1380428d7b3dSmrg return NULL; 1381428d7b3dSmrg 1382428d7b3dSmrg info = calloc(1, sizeof(struct sna_dri2_event)); 1383428d7b3dSmrg if (info == NULL) 1384428d7b3dSmrg return NULL; 1385428d7b3dSmrg 1386428d7b3dSmrg list_init(&info->cache); 1387428d7b3dSmrg info->sna = sna; 1388428d7b3dSmrg info->draw = draw; 1389428d7b3dSmrg info->crtc = priv->crtc; 1390428d7b3dSmrg info->pipe = sna_crtc_to_pipe(priv->crtc); 1391428d7b3dSmrg 1392428d7b3dSmrg if (!add_event_to_client(info, sna, client)) { 1393428d7b3dSmrg free(info); 1394428d7b3dSmrg return NULL; 1395428d7b3dSmrg } 1396428d7b3dSmrg 1397428d7b3dSmrg assert(priv->chain != info); 1398428d7b3dSmrg 1399428d7b3dSmrg if (priv->chain == NULL) { 1400428d7b3dSmrg priv->chain = info; 1401428d7b3dSmrg return info; 1402428d7b3dSmrg } 1403428d7b3dSmrg 1404428d7b3dSmrg chain = priv->chain; 1405428d7b3dSmrg while (chain->chain != NULL) 1406428d7b3dSmrg chain = chain->chain; 1407428d7b3dSmrg 1408428d7b3dSmrg assert(chain != info); 1409428d7b3dSmrg chain->chain = info; 1410428d7b3dSmrg return info; 1411428d7b3dSmrg} 1412428d7b3dSmrg 1413428d7b3dSmrgvoid sna_dri2_decouple_window(WindowPtr win) 1414428d7b3dSmrg{ 1415428d7b3dSmrg struct dri2_window *priv; 1416428d7b3dSmrg 1417428d7b3dSmrg priv = dri2_window(win); 1418428d7b3dSmrg if (priv == NULL) 1419428d7b3dSmrg return; 1420428d7b3dSmrg 1421428d7b3dSmrg DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 1422428d7b3dSmrg 1423428d7b3dSmrg if (priv->front) { 1424428d7b3dSmrg struct sna *sna = to_sna_from_drawable(&win->drawable); 1425428d7b3dSmrg assert(priv->crtc); 1426428d7b3dSmrg sna_shadow_unset_crtc(sna, priv->crtc); 1427428d7b3dSmrg _sna_dri2_destroy_buffer(sna, priv->front); 1428428d7b3dSmrg priv->front = NULL; 1429428d7b3dSmrg } 1430428d7b3dSmrg} 1431428d7b3dSmrg 1432428d7b3dSmrgvoid sna_dri2_destroy_window(WindowPtr win) 1433428d7b3dSmrg{ 1434428d7b3dSmrg struct dri2_window *priv; 1435428d7b3dSmrg 1436428d7b3dSmrg priv = dri2_window(win); 1437428d7b3dSmrg if (priv == NULL) 1438428d7b3dSmrg return; 1439428d7b3dSmrg 1440428d7b3dSmrg DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 1441428d7b3dSmrg 1442428d7b3dSmrg if (priv->front) { 1443428d7b3dSmrg struct sna *sna = to_sna_from_drawable(&win->drawable); 1444428d7b3dSmrg assert(priv->crtc); 1445428d7b3dSmrg sna_shadow_unset_crtc(sna, priv->crtc); 1446428d7b3dSmrg _sna_dri2_destroy_buffer(sna, priv->front); 1447428d7b3dSmrg } 1448428d7b3dSmrg 1449428d7b3dSmrg if (priv->chain) { 1450428d7b3dSmrg struct sna_dri2_event *info, *chain; 1451428d7b3dSmrg 1452428d7b3dSmrg DBG(("%s: freeing chain\n", __FUNCTION__)); 1453428d7b3dSmrg 1454428d7b3dSmrg chain = priv->chain; 1455428d7b3dSmrg while ((info = chain)) { 1456428d7b3dSmrg info->draw = NULL; 1457428d7b3dSmrg info->client = NULL; 1458428d7b3dSmrg list_del(&info->link); 1459428d7b3dSmrg 1460428d7b3dSmrg chain = info->chain; 1461428d7b3dSmrg info->chain = NULL; 1462428d7b3dSmrg 1463428d7b3dSmrg if (!info->queued) 1464428d7b3dSmrg sna_dri2_event_free(info); 1465428d7b3dSmrg } 1466428d7b3dSmrg } 1467428d7b3dSmrg 1468428d7b3dSmrg free(priv); 1469428d7b3dSmrg} 1470428d7b3dSmrg 1471428d7b3dSmrgstatic void 1472428d7b3dSmrgsna_dri2_flip_handler(struct drm_event_vblank *event, void *data) 1473428d7b3dSmrg{ 1474428d7b3dSmrg DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence)); 1475428d7b3dSmrg sna_dri2_flip_event(data); 1476428d7b3dSmrg} 1477428d7b3dSmrg 1478428d7b3dSmrgstatic bool 1479428d7b3dSmrgsna_dri2_flip(struct sna_dri2_event *info) 1480428d7b3dSmrg{ 1481428d7b3dSmrg struct kgem_bo *bo = get_private(info->back)->bo; 1482428d7b3dSmrg struct kgem_bo *tmp_bo; 1483428d7b3dSmrg uint32_t tmp_name; 1484428d7b3dSmrg int tmp_pitch; 1485428d7b3dSmrg 1486428d7b3dSmrg DBG(("%s(type=%d)\n", __FUNCTION__, info->type)); 1487428d7b3dSmrg 1488428d7b3dSmrg assert(sna_pixmap_get_buffer(info->sna->front) == info->front); 1489428d7b3dSmrg assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo)); 1490428d7b3dSmrg assert(bo->refcnt); 1491428d7b3dSmrg 1492428d7b3dSmrg if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, 1493428d7b3dSmrg info->type == FLIP_ASYNC ? NULL : info)) 1494428d7b3dSmrg return false; 1495428d7b3dSmrg 1496428d7b3dSmrg assert(info->sna->dri2.flip_pending == NULL || 1497428d7b3dSmrg info->sna->dri2.flip_pending == info); 1498428d7b3dSmrg if (info->type != FLIP_ASYNC) 1499428d7b3dSmrg info->sna->dri2.flip_pending = info; 1500428d7b3dSmrg 1501428d7b3dSmrg DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n", 1502428d7b3dSmrg __FUNCTION__, bo->handle, 1503428d7b3dSmrg get_private(info->front)->bo->handle, info->front->name, 1504428d7b3dSmrg get_private(info->back)->bo->handle, info->back->name)); 1505428d7b3dSmrg 1506428d7b3dSmrg tmp_bo = get_private(info->front)->bo; 1507428d7b3dSmrg tmp_name = info->front->name; 1508428d7b3dSmrg tmp_pitch = info->front->pitch; 1509428d7b3dSmrg 1510428d7b3dSmrg set_bo(info->sna->front, bo); 1511428d7b3dSmrg 1512428d7b3dSmrg info->front->name = info->back->name; 1513428d7b3dSmrg info->front->pitch = info->back->pitch; 1514428d7b3dSmrg get_private(info->front)->bo = bo; 1515428d7b3dSmrg 1516428d7b3dSmrg info->back->name = tmp_name; 1517428d7b3dSmrg info->back->pitch = tmp_pitch; 1518428d7b3dSmrg get_private(info->back)->bo = tmp_bo; 1519428d7b3dSmrg mark_stale(info->back); 1520428d7b3dSmrg 1521428d7b3dSmrg assert(get_private(info->front)->bo->refcnt); 1522428d7b3dSmrg assert(get_private(info->back)->bo->refcnt); 1523428d7b3dSmrg assert(get_private(info->front)->bo != get_private(info->back)->bo); 1524428d7b3dSmrg 1525428d7b3dSmrg info->queued = true; 1526428d7b3dSmrg return true; 1527428d7b3dSmrg} 1528428d7b3dSmrg 1529428d7b3dSmrgstatic bool 1530428d7b3dSmrgcan_flip(struct sna * sna, 1531428d7b3dSmrg DrawablePtr draw, 1532428d7b3dSmrg DRI2BufferPtr front, 1533428d7b3dSmrg DRI2BufferPtr back, 1534428d7b3dSmrg xf86CrtcPtr crtc) 1535428d7b3dSmrg{ 1536428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 1537428d7b3dSmrg PixmapPtr pixmap; 1538428d7b3dSmrg 1539428d7b3dSmrg assert((sna->flags & SNA_NO_WAIT) == 0); 1540428d7b3dSmrg 1541428d7b3dSmrg if (!DBG_CAN_FLIP) 1542428d7b3dSmrg return false; 1543428d7b3dSmrg 1544428d7b3dSmrg if (draw->type == DRAWABLE_PIXMAP) 1545428d7b3dSmrg return false; 1546428d7b3dSmrg 1547428d7b3dSmrg if (!sna->mode.front_active) { 1548428d7b3dSmrg DBG(("%s: no, active CRTC\n", __FUNCTION__)); 1549428d7b3dSmrg return false; 1550428d7b3dSmrg } 1551428d7b3dSmrg 1552428d7b3dSmrg assert(sna->scrn->vtSema); 1553428d7b3dSmrg 1554428d7b3dSmrg if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) { 1555428d7b3dSmrg DBG(("%s: no, pageflips disabled\n", __FUNCTION__)); 1556428d7b3dSmrg return false; 1557428d7b3dSmrg } 1558428d7b3dSmrg 1559428d7b3dSmrg if (front->format != back->format) { 1560428d7b3dSmrg DBG(("%s: no, format mismatch, front = %d, back = %d\n", 1561428d7b3dSmrg __FUNCTION__, front->format, back->format)); 1562428d7b3dSmrg return false; 1563428d7b3dSmrg } 1564428d7b3dSmrg 1565428d7b3dSmrg if (sna->mode.shadow_active) { 1566428d7b3dSmrg DBG(("%s: no, shadow enabled\n", __FUNCTION__)); 1567428d7b3dSmrg return false; 1568428d7b3dSmrg } 1569428d7b3dSmrg 1570428d7b3dSmrg if (!sna_crtc_is_on(crtc)) { 1571428d7b3dSmrg DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc))); 1572428d7b3dSmrg return false; 1573428d7b3dSmrg } 1574428d7b3dSmrg 1575428d7b3dSmrg pixmap = get_window_pixmap(win); 1576428d7b3dSmrg if (pixmap != sna->front) { 1577428d7b3dSmrg DBG(("%s: no, window (pixmap=%ld) is not attached to the front buffer (pixmap=%ld)\n", 1578428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber, sna->front->drawable.serialNumber)); 1579428d7b3dSmrg return false; 1580428d7b3dSmrg } 1581428d7b3dSmrg 1582428d7b3dSmrg if (sna_pixmap_get_buffer(pixmap) != front) { 1583428d7b3dSmrg DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n", 1584428d7b3dSmrg __FUNCTION__, front->name, 1585428d7b3dSmrg sna_pixmap_get_buffer(pixmap) ? ((DRI2BufferPtr)sna_pixmap_get_buffer(pixmap))->name : 0, 1586428d7b3dSmrg pixmap->drawable.serialNumber)); 1587428d7b3dSmrg return false; 1588428d7b3dSmrg } 1589428d7b3dSmrg 1590428d7b3dSmrg assert(get_private(front)->pixmap == sna->front); 1591428d7b3dSmrg assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo); 1592428d7b3dSmrg 1593428d7b3dSmrg if (!get_private(back)->bo->scanout) { 1594428d7b3dSmrg DBG(("%s: no, DRI2 drawable was too small at time of creation)\n", 1595428d7b3dSmrg __FUNCTION__)); 1596428d7b3dSmrg return false; 1597428d7b3dSmrg } 1598428d7b3dSmrg 1599428d7b3dSmrg if (get_private(back)->size != get_private(front)->size) { 1600428d7b3dSmrg DBG(("%s: no, DRI2 drawable does not fit into scanout\n", 1601428d7b3dSmrg __FUNCTION__)); 1602428d7b3dSmrg return false; 1603428d7b3dSmrg } 1604428d7b3dSmrg 1605428d7b3dSmrg DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n", 1606428d7b3dSmrg __FUNCTION__, 1607428d7b3dSmrg win->drawable.width, win->drawable.height, 1608428d7b3dSmrg win->clipList.extents.x1, win->clipList.extents.y1, 1609428d7b3dSmrg win->clipList.extents.x2, win->clipList.extents.y2, 1610428d7b3dSmrg region_num_rects(&win->clipList))); 1611428d7b3dSmrg if (!RegionEqual(&win->clipList, &draw->pScreen->root->winSize)) { 1612428d7b3dSmrg DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n", 1613428d7b3dSmrg __FUNCTION__, 1614428d7b3dSmrg win->clipList.extents.x1, 1615428d7b3dSmrg win->clipList.extents.y1, 1616428d7b3dSmrg win->clipList.extents.x2, 1617428d7b3dSmrg win->clipList.extents.y2, 1618428d7b3dSmrg draw->pScreen->root->winSize.extents.x1, 1619428d7b3dSmrg draw->pScreen->root->winSize.extents.y1, 1620428d7b3dSmrg draw->pScreen->root->winSize.extents.x2, 1621428d7b3dSmrg draw->pScreen->root->winSize.extents.y2)); 1622428d7b3dSmrg return false; 1623428d7b3dSmrg } 1624428d7b3dSmrg 1625428d7b3dSmrg if (draw->x != 0 || draw->y != 0 || 1626428d7b3dSmrg#ifdef COMPOSITE 1627428d7b3dSmrg draw->x != pixmap->screen_x || 1628428d7b3dSmrg draw->y != pixmap->screen_y || 1629428d7b3dSmrg#endif 1630428d7b3dSmrg draw->width != pixmap->drawable.width || 1631428d7b3dSmrg draw->height != pixmap->drawable.height) { 1632428d7b3dSmrg DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n", 1633428d7b3dSmrg __FUNCTION__, 1634428d7b3dSmrg draw->width, draw->height, 1635428d7b3dSmrg pixmap->drawable.width, 1636428d7b3dSmrg pixmap->drawable.height)); 1637428d7b3dSmrg return false; 1638428d7b3dSmrg } 1639428d7b3dSmrg 1640428d7b3dSmrg /* prevent an implicit tiling mode change */ 1641428d7b3dSmrg if (get_private(back)->bo->tiling > I915_TILING_X) { 1642428d7b3dSmrg DBG(("%s -- no, tiling mismatch: front %d, back=%d, want-tiled?=%d\n", 1643428d7b3dSmrg __FUNCTION__, 1644428d7b3dSmrg get_private(front)->bo->tiling, 1645428d7b3dSmrg get_private(back)->bo->tiling, 1646428d7b3dSmrg !!(sna->flags & SNA_LINEAR_FB))); 1647428d7b3dSmrg return false; 1648428d7b3dSmrg } 1649428d7b3dSmrg 1650428d7b3dSmrg if (get_private(front)->bo->pitch != get_private(back)->bo->pitch) { 1651428d7b3dSmrg DBG(("%s -- no, pitch mismatch: front %d, back=%d\n", 1652428d7b3dSmrg __FUNCTION__, 1653428d7b3dSmrg get_private(front)->bo->pitch, 1654428d7b3dSmrg get_private(back)->bo->pitch)); 1655428d7b3dSmrg return false; 1656428d7b3dSmrg } 1657428d7b3dSmrg 1658428d7b3dSmrg if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) { 1659428d7b3dSmrg DBG(("%s -- no, pinned: front %x\n", 1660428d7b3dSmrg __FUNCTION__, sna_pixmap(pixmap)->pinned)); 1661428d7b3dSmrg return false; 1662428d7b3dSmrg } 1663428d7b3dSmrg 1664428d7b3dSmrg DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1665428d7b3dSmrg assert(dri2_window(win)->front == NULL); 1666428d7b3dSmrg return true; 1667428d7b3dSmrg} 1668428d7b3dSmrg 1669428d7b3dSmrgstatic bool 1670428d7b3dSmrgcan_xchg(struct sna *sna, 1671428d7b3dSmrg DrawablePtr draw, 1672428d7b3dSmrg DRI2BufferPtr front, 1673428d7b3dSmrg DRI2BufferPtr back) 1674428d7b3dSmrg{ 1675428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 1676428d7b3dSmrg PixmapPtr pixmap; 1677428d7b3dSmrg 1678428d7b3dSmrg if (!DBG_CAN_XCHG) 1679428d7b3dSmrg return false; 1680428d7b3dSmrg 1681428d7b3dSmrg if (draw->type == DRAWABLE_PIXMAP) 1682428d7b3dSmrg return false; 1683428d7b3dSmrg 1684428d7b3dSmrg if (front->format != back->format) { 1685428d7b3dSmrg DBG(("%s: no, format mismatch, front = %d, back = %d\n", 1686428d7b3dSmrg __FUNCTION__, front->format, back->format)); 1687428d7b3dSmrg return false; 1688428d7b3dSmrg } 1689428d7b3dSmrg 1690428d7b3dSmrg pixmap = get_window_pixmap(win); 1691428d7b3dSmrg if (get_private(front)->pixmap != pixmap) { 1692428d7b3dSmrg DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n", 1693428d7b3dSmrg __FUNCTION__, 1694428d7b3dSmrg get_private(front)->pixmap->drawable.serialNumber, 1695428d7b3dSmrg pixmap->drawable.serialNumber)); 1696428d7b3dSmrg return false; 1697428d7b3dSmrg } 1698428d7b3dSmrg 1699428d7b3dSmrg DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d, pixmap size=%dx%d\n", 1700428d7b3dSmrg __FUNCTION__, 1701428d7b3dSmrg win->drawable.width, win->drawable.height, 1702428d7b3dSmrg win->clipList.extents.x1, win->clipList.extents.y1, 1703428d7b3dSmrg win->clipList.extents.x2, win->clipList.extents.y2, 1704428d7b3dSmrg region_num_rects(&win->clipList), 1705428d7b3dSmrg pixmap->drawable.width, 1706428d7b3dSmrg pixmap->drawable.height)); 1707428d7b3dSmrg if (is_clipped(&win->clipList, &pixmap->drawable)) { 1708428d7b3dSmrg DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n", 1709428d7b3dSmrg __FUNCTION__, 1710428d7b3dSmrg draw->width, draw->height, 1711428d7b3dSmrg win->clipList.extents.x1, 1712428d7b3dSmrg win->clipList.extents.y1, 1713428d7b3dSmrg win->clipList.extents.x2, 1714428d7b3dSmrg win->clipList.extents.y2)); 1715428d7b3dSmrg return false; 1716428d7b3dSmrg } 1717428d7b3dSmrg 1718428d7b3dSmrg if (get_private(back)->size != get_private(front)->size) { 1719428d7b3dSmrg DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n", 1720428d7b3dSmrg __FUNCTION__, 1721428d7b3dSmrg get_private(back)->size & 0x7fff, (get_private(back)->size >> 16) & 0x7fff, 1722428d7b3dSmrg get_private(front)->size & 0x7fff, (get_private(front)->size >> 16) & 0x7fff)); 1723428d7b3dSmrg return false; 1724428d7b3dSmrg } 1725428d7b3dSmrg 1726428d7b3dSmrg if (pixmap == sna->front && !(sna->flags & SNA_TEAR_FREE) && sna->mode.front_active) { 1727428d7b3dSmrg DBG(("%s: no, front buffer, requires flipping\n", 1728428d7b3dSmrg __FUNCTION__)); 1729428d7b3dSmrg return false; 1730428d7b3dSmrg } 1731428d7b3dSmrg 1732428d7b3dSmrg if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) { 1733428d7b3dSmrg DBG(("%s: no, pinned: %x\n", 1734428d7b3dSmrg __FUNCTION__, sna_pixmap(pixmap)->pinned)); 1735428d7b3dSmrg return false; 1736428d7b3dSmrg } 1737428d7b3dSmrg 1738428d7b3dSmrg DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1739428d7b3dSmrg return true; 1740428d7b3dSmrg} 1741428d7b3dSmrg 1742428d7b3dSmrgstatic bool 1743428d7b3dSmrgoverlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired) 1744428d7b3dSmrg{ 1745428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 1746428d7b3dSmrg int c; 1747428d7b3dSmrg 1748428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 1749428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[c]; 1750428d7b3dSmrg 1751428d7b3dSmrg if (crtc == desired) 1752428d7b3dSmrg continue; 1753428d7b3dSmrg 1754428d7b3dSmrg if (!crtc->enabled) 1755428d7b3dSmrg continue; 1756428d7b3dSmrg 1757428d7b3dSmrg if (desired->bounds.x1 < crtc->bounds.x2 && 1758428d7b3dSmrg desired->bounds.x2 > crtc->bounds.x1 && 1759428d7b3dSmrg desired->bounds.y1 < crtc->bounds.y2 && 1760428d7b3dSmrg desired->bounds.y2 > crtc->bounds.y1) 1761428d7b3dSmrg return true; 1762428d7b3dSmrg } 1763428d7b3dSmrg 1764428d7b3dSmrg return false; 1765428d7b3dSmrg} 1766428d7b3dSmrg 1767428d7b3dSmrgstatic bool 1768428d7b3dSmrgcan_xchg_crtc(struct sna *sna, 1769428d7b3dSmrg DrawablePtr draw, 1770428d7b3dSmrg DRI2BufferPtr front, 1771428d7b3dSmrg DRI2BufferPtr back, 1772428d7b3dSmrg xf86CrtcPtr crtc) 1773428d7b3dSmrg{ 1774428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 1775428d7b3dSmrg PixmapPtr pixmap; 1776428d7b3dSmrg 1777428d7b3dSmrg if (!DBG_CAN_XCHG) 1778428d7b3dSmrg return false; 1779428d7b3dSmrg 1780428d7b3dSmrg if ((sna->flags & SNA_TEAR_FREE) == 0) { 1781428d7b3dSmrg DBG(("%s: no, requires TearFree\n", 1782428d7b3dSmrg __FUNCTION__)); 1783428d7b3dSmrg return false; 1784428d7b3dSmrg } 1785428d7b3dSmrg 1786428d7b3dSmrg if (draw->type == DRAWABLE_PIXMAP) 1787428d7b3dSmrg return false; 1788428d7b3dSmrg 1789428d7b3dSmrg if (front->format != back->format) { 1790428d7b3dSmrg DBG(("%s: no, format mismatch, front = %d, back = %d\n", 1791428d7b3dSmrg __FUNCTION__, front->format, back->format)); 1792428d7b3dSmrg return false; 1793428d7b3dSmrg } 1794428d7b3dSmrg 1795428d7b3dSmrg if (memcmp(&win->clipList.extents, &crtc->bounds, sizeof(crtc->bounds))) { 1796428d7b3dSmrg DBG(("%s: no, window [(%d, %d), (%d, %d)] does not cover CRTC [(%d, %d), (%d, %d)]\n", 1797428d7b3dSmrg __FUNCTION__, 1798428d7b3dSmrg win->clipList.extents.x1, win->clipList.extents.y1, 1799428d7b3dSmrg win->clipList.extents.x2, win->clipList.extents.y2, 1800428d7b3dSmrg crtc->bounds.x1, crtc->bounds.y1, 1801428d7b3dSmrg crtc->bounds.x2, crtc->bounds.y2)); 1802428d7b3dSmrg return false; 1803428d7b3dSmrg } 1804428d7b3dSmrg 1805428d7b3dSmrg if (sna_crtc_is_transformed(crtc)) { 1806428d7b3dSmrg DBG(("%s: no, CRTC is rotated\n", __FUNCTION__)); 1807428d7b3dSmrg return false; 1808428d7b3dSmrg } 1809428d7b3dSmrg 1810428d7b3dSmrg pixmap = get_window_pixmap(win); 1811428d7b3dSmrg if (pixmap != sna->front) { 1812428d7b3dSmrg DBG(("%s: no, not attached to front buffer\n", __FUNCTION__)); 1813428d7b3dSmrg return false; 1814428d7b3dSmrg } 1815428d7b3dSmrg 1816428d7b3dSmrg if (get_private(front)->pixmap != pixmap) { 1817428d7b3dSmrg DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n", 1818428d7b3dSmrg __FUNCTION__, 1819428d7b3dSmrg get_private(front)->pixmap->drawable.serialNumber, 1820428d7b3dSmrg pixmap->drawable.serialNumber)); 1821428d7b3dSmrg return false; 1822428d7b3dSmrg } 1823428d7b3dSmrg 1824428d7b3dSmrg DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n", 1825428d7b3dSmrg __FUNCTION__, 1826428d7b3dSmrg win->drawable.width, win->drawable.height, 1827428d7b3dSmrg win->clipList.extents.x1, win->clipList.extents.y1, 1828428d7b3dSmrg win->clipList.extents.x2, win->clipList.extents.y2, 1829428d7b3dSmrg region_num_rects(&win->clipList))); 1830428d7b3dSmrg if (is_clipped(&win->clipList, &win->drawable)) { 1831428d7b3dSmrg DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n", 1832428d7b3dSmrg __FUNCTION__, 1833428d7b3dSmrg draw->width, draw->height, 1834428d7b3dSmrg win->clipList.extents.x1, 1835428d7b3dSmrg win->clipList.extents.y1, 1836428d7b3dSmrg win->clipList.extents.x2, 1837428d7b3dSmrg win->clipList.extents.y2)); 1838428d7b3dSmrg return false; 1839428d7b3dSmrg } 1840428d7b3dSmrg 1841428d7b3dSmrg if (overlaps_other_crtc(sna, crtc)) { 1842428d7b3dSmrg DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__)); 1843428d7b3dSmrg return false; 1844428d7b3dSmrg } 1845428d7b3dSmrg 1846428d7b3dSmrg if (get_private(back)->size != (draw->height << 16 | draw->width)) { 1847428d7b3dSmrg DBG(("%s: no, DRI2 buffers does not fit window\n", 1848428d7b3dSmrg __FUNCTION__)); 1849428d7b3dSmrg return false; 1850428d7b3dSmrg } 1851428d7b3dSmrg 1852428d7b3dSmrg assert(win != win->drawable.pScreen->root); 1853428d7b3dSmrg DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1854428d7b3dSmrg return true; 1855428d7b3dSmrg} 1856428d7b3dSmrg 1857428d7b3dSmrgstatic void 1858428d7b3dSmrgsna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 1859428d7b3dSmrg{ 1860428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 1861428d7b3dSmrg struct kgem_bo *back_bo, *front_bo; 1862428d7b3dSmrg PixmapPtr pixmap; 1863428d7b3dSmrg int tmp; 1864428d7b3dSmrg 1865428d7b3dSmrg assert(draw->type != DRAWABLE_PIXMAP); 1866428d7b3dSmrg pixmap = get_window_pixmap(win); 1867428d7b3dSmrg 1868428d7b3dSmrg back_bo = get_private(back)->bo; 1869428d7b3dSmrg front_bo = get_private(front)->bo; 1870428d7b3dSmrg assert(front_bo != back_bo); 1871428d7b3dSmrg 1872428d7b3dSmrg DBG(("%s: win=%ld, exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n", 1873428d7b3dSmrg __FUNCTION__, win->drawable.id, 1874428d7b3dSmrg front_bo->handle, front->name, 1875428d7b3dSmrg back_bo->handle, back->name, 1876428d7b3dSmrg pixmap->drawable.serialNumber, 1877428d7b3dSmrg pixmap->drawable.width, 1878428d7b3dSmrg pixmap->drawable.height)); 1879428d7b3dSmrg 1880428d7b3dSmrg DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n", 1881428d7b3dSmrg __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout)); 1882428d7b3dSmrg DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n", 1883428d7b3dSmrg __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout)); 1884428d7b3dSmrg assert(front_bo->refcnt); 1885428d7b3dSmrg assert(back_bo->refcnt); 1886428d7b3dSmrg 1887428d7b3dSmrg assert(sna_pixmap_get_buffer(pixmap) == front); 1888428d7b3dSmrg 1889428d7b3dSmrg assert(pixmap->drawable.height * back_bo->pitch <= kgem_bo_size(back_bo)); 1890428d7b3dSmrg assert(pixmap->drawable.height * front_bo->pitch <= kgem_bo_size(front_bo)); 1891428d7b3dSmrg 1892428d7b3dSmrg set_bo(pixmap, back_bo); 1893428d7b3dSmrg 1894428d7b3dSmrg get_private(front)->bo = back_bo; 1895428d7b3dSmrg get_private(back)->bo = front_bo; 1896428d7b3dSmrg mark_stale(back); 1897428d7b3dSmrg 1898428d7b3dSmrg tmp = front->name; 1899428d7b3dSmrg front->name = back->name; 1900428d7b3dSmrg back->name = tmp; 1901428d7b3dSmrg 1902428d7b3dSmrg tmp = front->pitch; 1903428d7b3dSmrg front->pitch = back->pitch; 1904428d7b3dSmrg back->pitch = tmp; 1905428d7b3dSmrg 1906428d7b3dSmrg assert(front_bo->refcnt); 1907428d7b3dSmrg assert(back_bo->refcnt); 1908428d7b3dSmrg 1909428d7b3dSmrg assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo); 1910428d7b3dSmrg} 1911428d7b3dSmrg 1912428d7b3dSmrgstatic void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back) 1913428d7b3dSmrg{ 1914428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 1915428d7b3dSmrg DRI2Buffer2Ptr tmp; 1916428d7b3dSmrg struct kgem_bo *bo; 1917428d7b3dSmrg 1918428d7b3dSmrg DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n", 1919428d7b3dSmrg __FUNCTION__, 1920428d7b3dSmrg get_private(front)->bo->handle, front->name, 1921428d7b3dSmrg get_private(back)->bo->handle, back->name, 1922428d7b3dSmrg win->drawable.id, 1923428d7b3dSmrg get_window_pixmap(win)->drawable.serialNumber, 1924428d7b3dSmrg get_window_pixmap(win)->drawable.width, 1925428d7b3dSmrg get_window_pixmap(win)->drawable.height)); 1926428d7b3dSmrg 1927428d7b3dSmrg DamageRegionAppend(&win->drawable, &win->clipList); 1928428d7b3dSmrg sna_shadow_set_crtc(sna, crtc, get_private(back)->bo); 1929428d7b3dSmrg DamageRegionProcessPending(&win->drawable); 1930428d7b3dSmrg 1931428d7b3dSmrg assert(dri2_window(win)->front == NULL); 1932428d7b3dSmrg 1933428d7b3dSmrg tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private)); 1934428d7b3dSmrg if (tmp == NULL) { 1935428d7b3dSmrg back->attachment = -1; 1936428d7b3dSmrg if (get_private(back)->proxy == NULL) { 1937428d7b3dSmrg get_private(back)->pixmap = get_window_pixmap(win); 1938428d7b3dSmrg get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap)); 1939428d7b3dSmrg } 1940428d7b3dSmrg dri2_window(win)->front = sna_dri2_reference_buffer(back); 1941428d7b3dSmrg return; 1942428d7b3dSmrg } 1943428d7b3dSmrg 1944428d7b3dSmrg *tmp = *back; 1945428d7b3dSmrg tmp->attachment = DRI2BufferFrontLeft; 1946428d7b3dSmrg tmp->driverPrivate = tmp + 1; 1947428d7b3dSmrg get_private(tmp)->refcnt = 1; 1948428d7b3dSmrg get_private(tmp)->bo = get_private(back)->bo; 1949428d7b3dSmrg get_private(tmp)->size = get_private(back)->size; 1950428d7b3dSmrg get_private(tmp)->pixmap = get_window_pixmap(win); 1951428d7b3dSmrg get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap)); 1952428d7b3dSmrg dri2_window(win)->front = tmp; 1953428d7b3dSmrg 1954428d7b3dSmrg DBG(("%s: allocating new backbuffer\n", __FUNCTION__)); 1955428d7b3dSmrg back->name = 0; 1956428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 1957428d7b3dSmrg draw->width, draw->height, draw->bitsPerPixel, 1958428d7b3dSmrg get_private(back)->bo->tiling, 1959428d7b3dSmrg CREATE_SCANOUT); 1960428d7b3dSmrg if (bo != NULL) { 1961428d7b3dSmrg get_private(back)->bo = bo; 1962428d7b3dSmrg back->pitch = bo->pitch; 1963428d7b3dSmrg back->name = kgem_bo_flink(&sna->kgem, bo); 1964428d7b3dSmrg } 1965428d7b3dSmrg if (back->name == 0) { 1966428d7b3dSmrg if (bo != NULL) 1967428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1968428d7b3dSmrg get_private(back)->bo = NULL; 1969428d7b3dSmrg back->attachment = -1; 1970428d7b3dSmrg } 1971428d7b3dSmrg} 1972428d7b3dSmrg 1973428d7b3dSmrgstatic void frame_swap_complete(struct sna_dri2_event *frame, int type) 1974428d7b3dSmrg{ 1975428d7b3dSmrg const struct ust_msc *swap; 1976428d7b3dSmrg 1977428d7b3dSmrg if (frame->draw == NULL) 1978428d7b3dSmrg return; 1979428d7b3dSmrg 1980428d7b3dSmrg assert(frame->client); 1981428d7b3dSmrg 1982428d7b3dSmrg swap = sna_crtc_last_swap(frame->crtc); 1983428d7b3dSmrg DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n", 1984428d7b3dSmrg __FUNCTION__, type, (long)frame->draw, frame->pipe, 1985428d7b3dSmrg (long long)swap->msc, 1986428d7b3dSmrg (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc), 1987428d7b3dSmrg swap->tv_sec, swap->tv_usec)); 1988428d7b3dSmrg 1989428d7b3dSmrg DRI2SwapComplete(frame->client, frame->draw, 1990428d7b3dSmrg draw_current_msc(frame->draw, frame->crtc, swap->msc), 1991428d7b3dSmrg swap->tv_sec, swap->tv_usec, 1992428d7b3dSmrg type, frame->event_complete, frame->event_data); 1993428d7b3dSmrg} 1994428d7b3dSmrg 1995428d7b3dSmrgstatic void fake_swap_complete(struct sna *sna, ClientPtr client, 1996428d7b3dSmrg DrawablePtr draw, xf86CrtcPtr crtc, 1997428d7b3dSmrg int type, DRI2SwapEventPtr func, void *data) 1998428d7b3dSmrg{ 1999428d7b3dSmrg const struct ust_msc *swap; 2000428d7b3dSmrg 2001428d7b3dSmrg swap = sna_crtc_last_swap(crtc); 2002428d7b3dSmrg DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n", 2003428d7b3dSmrg __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1, 2004428d7b3dSmrg (long long)swap->msc, 2005428d7b3dSmrg (long long)draw_current_msc(draw, crtc, swap->msc), 2006428d7b3dSmrg swap->tv_sec, swap->tv_usec)); 2007428d7b3dSmrg 2008428d7b3dSmrg DRI2SwapComplete(client, draw, 2009428d7b3dSmrg draw_current_msc(draw, crtc, swap->msc), 2010428d7b3dSmrg swap->tv_sec, swap->tv_usec, 2011428d7b3dSmrg type, func, data); 2012428d7b3dSmrg} 2013428d7b3dSmrg 2014428d7b3dSmrgstatic void chain_swap(struct sna_dri2_event *chain) 2015428d7b3dSmrg{ 2016428d7b3dSmrg union drm_wait_vblank vbl; 2017428d7b3dSmrg 2018428d7b3dSmrg if (chain->draw == NULL) { 2019428d7b3dSmrg sna_dri2_event_free(chain); 2020428d7b3dSmrg return; 2021428d7b3dSmrg } 2022428d7b3dSmrg 2023428d7b3dSmrg if (chain->queued) /* too early! */ 2024428d7b3dSmrg return; 2025428d7b3dSmrg 2026428d7b3dSmrg assert(chain == dri2_chain(chain->draw)); 2027428d7b3dSmrg DBG(("%s: chaining draw=%ld, type=%d\n", 2028428d7b3dSmrg __FUNCTION__, (long)chain->draw->id, chain->type)); 2029428d7b3dSmrg chain->queued = true; 2030428d7b3dSmrg 2031428d7b3dSmrg switch (chain->type) { 2032428d7b3dSmrg case SWAP_THROTTLE: 2033428d7b3dSmrg DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); 2034428d7b3dSmrg if (chain->sna->mode.shadow && 2035428d7b3dSmrg !chain->sna->mode.shadow_damage) { 2036428d7b3dSmrg /* recursed from wait_for_shadow(), simply requeue */ 2037428d7b3dSmrg DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__)); 2038428d7b3dSmrg VG_CLEAR(vbl); 2039428d7b3dSmrg vbl.request.type = 2040428d7b3dSmrg DRM_VBLANK_RELATIVE | 2041428d7b3dSmrg DRM_VBLANK_EVENT; 2042428d7b3dSmrg vbl.request.sequence = 1; 2043428d7b3dSmrg vbl.request.signal = (uintptr_t)chain; 2044428d7b3dSmrg 2045428d7b3dSmrg if (!sna_wait_vblank(chain->sna, &vbl, chain->pipe)) 2046428d7b3dSmrg return; 2047428d7b3dSmrg 2048428d7b3dSmrg DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno)); 2049428d7b3dSmrg } 2050428d7b3dSmrg 2051428d7b3dSmrg if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) { 2052428d7b3dSmrg sna_dri2_xchg(chain->draw, chain->front, chain->back); 2053428d7b3dSmrg } else if (can_xchg_crtc(chain->sna, chain->draw, chain->front, chain->back, chain->crtc)) { 2054428d7b3dSmrg sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc, chain->front, chain->back); 2055428d7b3dSmrg } else { 2056428d7b3dSmrg assert(chain->queued); 2057428d7b3dSmrg chain->bo = __sna_dri2_copy_region(chain->sna, chain->draw, NULL, 2058428d7b3dSmrg chain->back, chain->front, 2059428d7b3dSmrg true); 2060428d7b3dSmrg } 2061428d7b3dSmrg case SWAP: 2062428d7b3dSmrg break; 2063428d7b3dSmrg default: 2064428d7b3dSmrg return; 2065428d7b3dSmrg } 2066428d7b3dSmrg 2067428d7b3dSmrg VG_CLEAR(vbl); 2068428d7b3dSmrg vbl.request.type = 2069428d7b3dSmrg DRM_VBLANK_RELATIVE | 2070428d7b3dSmrg DRM_VBLANK_EVENT; 2071428d7b3dSmrg vbl.request.sequence = 1; 2072428d7b3dSmrg vbl.request.signal = (uintptr_t)chain; 2073428d7b3dSmrg if (sna_wait_vblank(chain->sna, &vbl, chain->pipe)) { 2074428d7b3dSmrg DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__)); 2075428d7b3dSmrg frame_swap_complete(chain, DRI2_BLIT_COMPLETE); 2076428d7b3dSmrg sna_dri2_event_free(chain); 2077428d7b3dSmrg } else { 2078428d7b3dSmrg if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) { 2079428d7b3dSmrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 2080428d7b3dSmrg frame_swap_complete(chain, DRI2_BLIT_COMPLETE); 2081428d7b3dSmrg } 2082428d7b3dSmrg } 2083428d7b3dSmrg} 2084428d7b3dSmrg 2085428d7b3dSmrgstatic inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo) 2086428d7b3dSmrg{ 2087428d7b3dSmrg if (bo == NULL) 2088428d7b3dSmrg return false; 2089428d7b3dSmrg 2090428d7b3dSmrg DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__, 2091428d7b3dSmrg bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL)); 2092428d7b3dSmrg assert(bo->refcnt); 2093428d7b3dSmrg 2094428d7b3dSmrg if (bo->exec) 2095428d7b3dSmrg return true; 2096428d7b3dSmrg 2097428d7b3dSmrg if (bo->rq == NULL) 2098428d7b3dSmrg return false; 2099428d7b3dSmrg 2100428d7b3dSmrg return __kgem_busy(kgem, bo->handle); 2101428d7b3dSmrg} 2102428d7b3dSmrg 2103428d7b3dSmrgstatic bool sna_dri2_blit_complete(struct sna *sna, 2104428d7b3dSmrg struct sna_dri2_event *info) 2105428d7b3dSmrg{ 2106428d7b3dSmrg if (rq_is_busy(&sna->kgem, info->bo)) { 2107428d7b3dSmrg union drm_wait_vblank vbl; 2108428d7b3dSmrg 2109428d7b3dSmrg DBG(("%s: vsync'ed blit is still busy, postponing\n", 2110428d7b3dSmrg __FUNCTION__)); 2111428d7b3dSmrg 2112428d7b3dSmrg VG_CLEAR(vbl); 2113428d7b3dSmrg vbl.request.type = 2114428d7b3dSmrg DRM_VBLANK_RELATIVE | 2115428d7b3dSmrg DRM_VBLANK_EVENT; 2116428d7b3dSmrg vbl.request.sequence = 1; 2117428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2118428d7b3dSmrg assert(info->queued); 2119428d7b3dSmrg if (!sna_wait_vblank(sna, &vbl, info->pipe)) 2120428d7b3dSmrg return false; 2121428d7b3dSmrg } 2122428d7b3dSmrg 2123428d7b3dSmrg DBG(("%s: blit finished\n", __FUNCTION__)); 2124428d7b3dSmrg return true; 2125428d7b3dSmrg} 2126428d7b3dSmrg 2127428d7b3dSmrgvoid sna_dri2_vblank_handler(struct drm_event_vblank *event) 2128428d7b3dSmrg{ 2129428d7b3dSmrg struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data; 2130428d7b3dSmrg struct sna *sna = info->sna; 2131428d7b3dSmrg DrawablePtr draw; 2132428d7b3dSmrg union drm_wait_vblank vbl; 2133428d7b3dSmrg uint64_t msc; 2134428d7b3dSmrg 2135428d7b3dSmrg DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence)); 2136428d7b3dSmrg assert(info->queued); 2137428d7b3dSmrg msc = sna_crtc_record_event(info->crtc, event); 2138428d7b3dSmrg 2139428d7b3dSmrg draw = info->draw; 2140428d7b3dSmrg if (draw == NULL) { 2141428d7b3dSmrg DBG(("%s -- drawable gone\n", __FUNCTION__)); 2142428d7b3dSmrg goto done; 2143428d7b3dSmrg } 2144428d7b3dSmrg 2145428d7b3dSmrg switch (info->type) { 2146428d7b3dSmrg case FLIP: 2147428d7b3dSmrg /* If we can still flip... */ 2148428d7b3dSmrg if (can_flip(sna, draw, info->front, info->back, info->crtc) && 2149428d7b3dSmrg sna_dri2_flip(info)) 2150428d7b3dSmrg return; 2151428d7b3dSmrg 2152428d7b3dSmrg /* else fall through to blit */ 2153428d7b3dSmrg case SWAP: 2154428d7b3dSmrg assert(info->queued); 2155428d7b3dSmrg if (sna->mode.shadow && !sna->mode.shadow_damage) { 2156428d7b3dSmrg /* recursed from wait_for_shadow(), simply requeue */ 2157428d7b3dSmrg DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__)); 2158428d7b3dSmrg 2159428d7b3dSmrg } else if (can_xchg(info->sna, draw, info->front, info->back)) { 2160428d7b3dSmrg sna_dri2_xchg(draw, info->front, info->back); 2161428d7b3dSmrg info->type = SWAP_WAIT; 2162428d7b3dSmrg } else if (can_xchg_crtc(sna, draw, info->front, info->back, info->crtc)) { 2163428d7b3dSmrg sna_dri2_xchg_crtc(sna, draw, info->crtc, info->front, info->back); 2164428d7b3dSmrg info->type = SWAP_WAIT; 2165428d7b3dSmrg } else { 2166428d7b3dSmrg assert(info->queued); 2167428d7b3dSmrg info->bo = __sna_dri2_copy_region(sna, draw, NULL, 2168428d7b3dSmrg info->back, info->front, true); 2169428d7b3dSmrg info->type = SWAP_WAIT; 2170428d7b3dSmrg } 2171428d7b3dSmrg 2172428d7b3dSmrg VG_CLEAR(vbl); 2173428d7b3dSmrg vbl.request.type = 2174428d7b3dSmrg DRM_VBLANK_RELATIVE | 2175428d7b3dSmrg DRM_VBLANK_EVENT; 2176428d7b3dSmrg vbl.request.sequence = 1; 2177428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2178428d7b3dSmrg 2179428d7b3dSmrg assert(info->queued); 2180428d7b3dSmrg if (!sna_wait_vblank(sna, &vbl, info->pipe)) 2181428d7b3dSmrg return; 2182428d7b3dSmrg 2183428d7b3dSmrg DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno)); 2184428d7b3dSmrg /* fall through to SwapComplete */ 2185428d7b3dSmrg case SWAP_WAIT: 2186428d7b3dSmrg if (!sna_dri2_blit_complete(sna, info)) 2187428d7b3dSmrg return; 2188428d7b3dSmrg 2189428d7b3dSmrg DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__, 2190428d7b3dSmrg event->sequence, event->tv_sec, event->tv_usec)); 2191428d7b3dSmrg frame_swap_complete(info, DRI2_BLIT_COMPLETE); 2192428d7b3dSmrg break; 2193428d7b3dSmrg 2194428d7b3dSmrg case SWAP_THROTTLE: 2195428d7b3dSmrg DBG(("%s: %d complete, frame=%d tv=%d.%06d\n", 2196428d7b3dSmrg __FUNCTION__, info->type, 2197428d7b3dSmrg event->sequence, event->tv_sec, event->tv_usec)); 2198428d7b3dSmrg 2199428d7b3dSmrg if (xorg_can_triple_buffer()) { 2200428d7b3dSmrg if (!sna_dri2_blit_complete(sna, info)) 2201428d7b3dSmrg return; 2202428d7b3dSmrg 2203428d7b3dSmrg DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__, 2204428d7b3dSmrg event->sequence, event->tv_sec, event->tv_usec)); 2205428d7b3dSmrg frame_swap_complete(info, DRI2_BLIT_COMPLETE); 2206428d7b3dSmrg } 2207428d7b3dSmrg break; 2208428d7b3dSmrg 2209428d7b3dSmrg case WAITMSC: 2210428d7b3dSmrg assert(info->client); 2211428d7b3dSmrg DRI2WaitMSCComplete(info->client, draw, msc, 2212428d7b3dSmrg event->tv_sec, event->tv_usec); 2213428d7b3dSmrg break; 2214428d7b3dSmrg default: 2215428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 2216428d7b3dSmrg "%s: unknown vblank event received\n", __func__); 2217428d7b3dSmrg /* Unknown type */ 2218428d7b3dSmrg break; 2219428d7b3dSmrg } 2220428d7b3dSmrg 2221428d7b3dSmrg if (info->chain) { 2222428d7b3dSmrg assert(info->chain != info); 2223428d7b3dSmrg assert(info->draw == draw); 2224428d7b3dSmrg sna_dri2_remove_event((WindowPtr)draw, info); 2225428d7b3dSmrg chain_swap(info->chain); 2226428d7b3dSmrg info->draw = NULL; 2227428d7b3dSmrg } 2228428d7b3dSmrg 2229428d7b3dSmrgdone: 2230428d7b3dSmrg sna_dri2_event_free(info); 2231428d7b3dSmrg DBG(("%s complete\n", __FUNCTION__)); 2232428d7b3dSmrg} 2233428d7b3dSmrg 2234428d7b3dSmrgstatic bool 2235428d7b3dSmrgsna_dri2_immediate_blit(struct sna *sna, 2236428d7b3dSmrg struct sna_dri2_event *info, 2237428d7b3dSmrg bool sync, bool event) 2238428d7b3dSmrg{ 2239428d7b3dSmrg DrawablePtr draw = info->draw; 2240428d7b3dSmrg bool ret = false; 2241428d7b3dSmrg 2242428d7b3dSmrg if (sna->flags & SNA_NO_WAIT) 2243428d7b3dSmrg sync = false; 2244428d7b3dSmrg 2245428d7b3dSmrg DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, send-event? %d\n", 2246428d7b3dSmrg __FUNCTION__, sync, dri2_chain(draw) != info, 2247428d7b3dSmrg event)); 2248428d7b3dSmrg 2249428d7b3dSmrg info->type = SWAP_THROTTLE; 2250428d7b3dSmrg if (!sync || dri2_chain(draw) == info) { 2251428d7b3dSmrg DBG(("%s: no pending blit, starting chain\n", 2252428d7b3dSmrg __FUNCTION__)); 2253428d7b3dSmrg 2254428d7b3dSmrg info->queued = true; 2255428d7b3dSmrg info->bo = __sna_dri2_copy_region(sna, draw, NULL, 2256428d7b3dSmrg info->back, 2257428d7b3dSmrg info->front, 2258428d7b3dSmrg sync); 2259428d7b3dSmrg if (event) { 2260428d7b3dSmrg if (sync) { 2261428d7b3dSmrg union drm_wait_vblank vbl; 2262428d7b3dSmrg 2263428d7b3dSmrg VG_CLEAR(vbl); 2264428d7b3dSmrg vbl.request.type = 2265428d7b3dSmrg DRM_VBLANK_RELATIVE | 2266428d7b3dSmrg DRM_VBLANK_EVENT; 2267428d7b3dSmrg vbl.request.sequence = 1; 2268428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2269428d7b3dSmrg ret = !sna_wait_vblank(sna, &vbl, info->pipe); 2270428d7b3dSmrg if (ret) 2271428d7b3dSmrg event = !swap_limit(draw, 2); 2272428d7b3dSmrg } 2273428d7b3dSmrg if (event) { 2274428d7b3dSmrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 2275428d7b3dSmrg frame_swap_complete(info, DRI2_BLIT_COMPLETE); 2276428d7b3dSmrg } 2277428d7b3dSmrg } 2278428d7b3dSmrg } else { 2279428d7b3dSmrg DBG(("%s: pending blit, chained\n", __FUNCTION__)); 2280428d7b3dSmrg ret = true; 2281428d7b3dSmrg } 2282428d7b3dSmrg 2283428d7b3dSmrg DBG(("%s: continue? %d\n", __FUNCTION__, ret)); 2284428d7b3dSmrg return ret; 2285428d7b3dSmrg} 2286428d7b3dSmrg 2287428d7b3dSmrgstatic bool 2288428d7b3dSmrgsna_dri2_flip_continue(struct sna_dri2_event *info) 2289428d7b3dSmrg{ 2290428d7b3dSmrg DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode)); 2291428d7b3dSmrg 2292428d7b3dSmrg if (info->mode > 0){ 2293428d7b3dSmrg struct kgem_bo *bo = get_private(info->front)->bo; 2294428d7b3dSmrg 2295428d7b3dSmrg info->type = info->mode; 2296428d7b3dSmrg 2297428d7b3dSmrg if (bo != sna_pixmap(info->sna->front)->gpu_bo) 2298428d7b3dSmrg return false; 2299428d7b3dSmrg 2300428d7b3dSmrg if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info)) 2301428d7b3dSmrg return false; 2302428d7b3dSmrg 2303428d7b3dSmrg assert(info->sna->dri2.flip_pending == NULL || 2304428d7b3dSmrg info->sna->dri2.flip_pending == info); 2305428d7b3dSmrg info->sna->dri2.flip_pending = info; 2306428d7b3dSmrg assert(info->queued); 2307428d7b3dSmrg } else { 2308428d7b3dSmrg info->type = -info->mode; 2309428d7b3dSmrg 2310428d7b3dSmrg if (!info->draw) 2311428d7b3dSmrg return false; 2312428d7b3dSmrg 2313428d7b3dSmrg if (!can_flip(info->sna, info->draw, info->front, info->back, info->crtc)) 2314428d7b3dSmrg return false; 2315428d7b3dSmrg 2316428d7b3dSmrg assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front); 2317428d7b3dSmrg if (!sna_dri2_flip(info)) 2318428d7b3dSmrg return false; 2319428d7b3dSmrg 2320428d7b3dSmrg if (!xorg_can_triple_buffer()) { 2321428d7b3dSmrg sna_dri2_get_back(info->sna, info->draw, info->back, info); 2322428d7b3dSmrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 2323428d7b3dSmrg frame_swap_complete(info, DRI2_FLIP_COMPLETE); 2324428d7b3dSmrg } 2325428d7b3dSmrg } 2326428d7b3dSmrg 2327428d7b3dSmrg info->mode = 0; 2328428d7b3dSmrg return true; 2329428d7b3dSmrg} 2330428d7b3dSmrg 2331428d7b3dSmrgstatic void chain_flip(struct sna *sna) 2332428d7b3dSmrg{ 2333428d7b3dSmrg struct sna_dri2_event *chain = sna->dri2.flip_pending; 2334428d7b3dSmrg 2335428d7b3dSmrg assert(chain->type == FLIP); 2336428d7b3dSmrg DBG(("%s: chaining type=%d, cancelled?=%d\n", 2337428d7b3dSmrg __FUNCTION__, chain->type, chain->draw == NULL)); 2338428d7b3dSmrg 2339428d7b3dSmrg sna->dri2.flip_pending = NULL; 2340428d7b3dSmrg if (chain->draw == NULL) { 2341428d7b3dSmrg sna_dri2_event_free(chain); 2342428d7b3dSmrg return; 2343428d7b3dSmrg } 2344428d7b3dSmrg 2345428d7b3dSmrg assert(chain == dri2_chain(chain->draw)); 2346428d7b3dSmrg assert(!chain->queued); 2347428d7b3dSmrg chain->queued = true; 2348428d7b3dSmrg 2349428d7b3dSmrg if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) && 2350428d7b3dSmrg sna_dri2_flip(chain)) { 2351428d7b3dSmrg DBG(("%s: performing chained flip\n", __FUNCTION__)); 2352428d7b3dSmrg } else { 2353428d7b3dSmrg DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); 2354428d7b3dSmrg chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL, 2355428d7b3dSmrg chain->back, chain->front, 2356428d7b3dSmrg true); 2357428d7b3dSmrg 2358428d7b3dSmrg if (xorg_can_triple_buffer()) { 2359428d7b3dSmrg union drm_wait_vblank vbl; 2360428d7b3dSmrg 2361428d7b3dSmrg VG_CLEAR(vbl); 2362428d7b3dSmrg 2363428d7b3dSmrg chain->type = SWAP_WAIT; 2364428d7b3dSmrg vbl.request.type = 2365428d7b3dSmrg DRM_VBLANK_RELATIVE | 2366428d7b3dSmrg DRM_VBLANK_EVENT; 2367428d7b3dSmrg vbl.request.sequence = 1; 2368428d7b3dSmrg vbl.request.signal = (uintptr_t)chain; 2369428d7b3dSmrg 2370428d7b3dSmrg assert(chain->queued); 2371428d7b3dSmrg if (!sna_wait_vblank(sna, &vbl, chain->pipe)) 2372428d7b3dSmrg return; 2373428d7b3dSmrg } 2374428d7b3dSmrg 2375428d7b3dSmrg DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__)); 2376428d7b3dSmrg frame_swap_complete(chain, DRI2_BLIT_COMPLETE); 2377428d7b3dSmrg sna_dri2_event_free(chain); 2378428d7b3dSmrg } 2379428d7b3dSmrg} 2380428d7b3dSmrg 2381428d7b3dSmrgstatic void sna_dri2_flip_event(struct sna_dri2_event *flip) 2382428d7b3dSmrg{ 2383428d7b3dSmrg struct sna *sna = flip->sna; 2384428d7b3dSmrg 2385428d7b3dSmrg DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type)); 2386428d7b3dSmrg assert(flip->queued); 2387428d7b3dSmrg 2388428d7b3dSmrg if (sna->dri2.flip_pending == flip) 2389428d7b3dSmrg sna->dri2.flip_pending = NULL; 2390428d7b3dSmrg 2391428d7b3dSmrg /* We assume our flips arrive in order, so we don't check the frame */ 2392428d7b3dSmrg switch (flip->type) { 2393428d7b3dSmrg case FLIP: 2394428d7b3dSmrg DBG(("%s: swap complete, unblocking client\n", __FUNCTION__)); 2395428d7b3dSmrg frame_swap_complete(flip, DRI2_FLIP_COMPLETE); 2396428d7b3dSmrg sna_dri2_event_free(flip); 2397428d7b3dSmrg 2398428d7b3dSmrg if (sna->dri2.flip_pending) 2399428d7b3dSmrg chain_flip(sna); 2400428d7b3dSmrg break; 2401428d7b3dSmrg 2402428d7b3dSmrg case FLIP_THROTTLE: 2403428d7b3dSmrg DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__)); 2404428d7b3dSmrg frame_swap_complete(flip, DRI2_FLIP_COMPLETE); 2405428d7b3dSmrg case FLIP_COMPLETE: 2406428d7b3dSmrg if (sna->dri2.flip_pending) { 2407428d7b3dSmrg sna_dri2_event_free(flip); 2408428d7b3dSmrg chain_flip(sna); 2409428d7b3dSmrg } else if (!flip->mode) { 2410428d7b3dSmrg DBG(("%s: flip chain complete\n", __FUNCTION__)); 2411428d7b3dSmrg 2412428d7b3dSmrg if (flip->chain) { 2413428d7b3dSmrg sna_dri2_remove_event((WindowPtr)flip->draw, 2414428d7b3dSmrg flip); 2415428d7b3dSmrg chain_swap(flip->chain); 2416428d7b3dSmrg flip->draw = NULL; 2417428d7b3dSmrg } 2418428d7b3dSmrg 2419428d7b3dSmrg sna_dri2_event_free(flip); 2420428d7b3dSmrg } else if (!sna_dri2_flip_continue(flip)) { 2421428d7b3dSmrg DBG(("%s: no longer able to flip\n", __FUNCTION__)); 2422428d7b3dSmrg if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0)) 2423428d7b3dSmrg sna_dri2_event_free(flip); 2424428d7b3dSmrg } 2425428d7b3dSmrg break; 2426428d7b3dSmrg 2427428d7b3dSmrg default: /* Unknown type */ 2428428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 2429428d7b3dSmrg "%s: unknown vblank event received\n", __func__); 2430428d7b3dSmrg sna_dri2_event_free(flip); 2431428d7b3dSmrg if (sna->dri2.flip_pending) 2432428d7b3dSmrg chain_flip(sna); 2433428d7b3dSmrg break; 2434428d7b3dSmrg } 2435428d7b3dSmrg} 2436428d7b3dSmrg 2437428d7b3dSmrgstatic uint64_t 2438428d7b3dSmrgget_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc) 2439428d7b3dSmrg{ 2440428d7b3dSmrg union drm_wait_vblank vbl; 2441428d7b3dSmrg uint64_t ret = -1; 2442428d7b3dSmrg 2443428d7b3dSmrg VG_CLEAR(vbl); 2444428d7b3dSmrg vbl.request.type = _DRM_VBLANK_RELATIVE; 2445428d7b3dSmrg vbl.request.sequence = 0; 2446428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0) 2447428d7b3dSmrg ret = sna_crtc_record_vblank(crtc, &vbl); 2448428d7b3dSmrg 2449428d7b3dSmrg return draw_current_msc(draw, crtc, ret); 2450428d7b3dSmrg} 2451428d7b3dSmrg 2452428d7b3dSmrg#if defined(CHECK_FOR_COMPOSITOR) 2453428d7b3dSmrgstatic Bool find(pointer value, XID id, pointer cdata) 2454428d7b3dSmrg{ 2455428d7b3dSmrg return TRUE; 2456428d7b3dSmrg} 2457428d7b3dSmrg#endif 2458428d7b3dSmrg 2459428d7b3dSmrgstatic int use_triple_buffer(struct sna *sna, ClientPtr client, bool async) 2460428d7b3dSmrg{ 2461428d7b3dSmrg if ((sna->flags & SNA_TRIPLE_BUFFER) == 0) { 2462428d7b3dSmrg DBG(("%s: triple buffer disabled, using FLIP\n", __FUNCTION__)); 2463428d7b3dSmrg return FLIP; 2464428d7b3dSmrg } 2465428d7b3dSmrg 2466428d7b3dSmrg if (async) { 2467428d7b3dSmrg DBG(("%s: running async, using %s\n", __FUNCTION__, 2468428d7b3dSmrg sna->flags & SNA_HAS_ASYNC_FLIP ? "FLIP_ASYNC" : "FLIP_COMPLETE")); 2469428d7b3dSmrg return sna->flags & SNA_HAS_ASYNC_FLIP ? FLIP_ASYNC : FLIP_COMPLETE; 2470428d7b3dSmrg } 2471428d7b3dSmrg 2472428d7b3dSmrg if (xorg_can_triple_buffer()) { 2473428d7b3dSmrg DBG(("%s: triple buffer enabled, using FLIP_THROTTLE\n", __FUNCTION__)); 2474428d7b3dSmrg return FLIP_THROTTLE; 2475428d7b3dSmrg } 2476428d7b3dSmrg 2477428d7b3dSmrg#if defined(CHECK_FOR_COMPOSITOR) 2478428d7b3dSmrg /* Hack: Disable triple buffering for compositors */ 2479428d7b3dSmrg { 2480428d7b3dSmrg struct sna_client *priv = sna_client(client); 2481428d7b3dSmrg if (priv->is_compositor == 0) 2482428d7b3dSmrg priv->is_compositor = 2483428d7b3dSmrg LookupClientResourceComplex(client, 2484428d7b3dSmrg CompositeClientWindowType+1, 2485428d7b3dSmrg find, NULL) ? FLIP : FLIP_COMPLETE; 2486428d7b3dSmrg 2487428d7b3dSmrg DBG(("%s: fake triple buffer enabled?=%d using %s\n", __FUNCTION__, 2488428d7b3dSmrg priv->is_compositor != FLIP, priv->is_compositor == FLIP ? "FLIP" : "FLIP_COMPLETE")); 2489428d7b3dSmrg return priv->is_compositor; 2490428d7b3dSmrg } 2491428d7b3dSmrg#else 2492428d7b3dSmrg DBG(("%s: fake triple buffer enabled, using FLIP_COMPLETE\n", __FUNCTION__)); 2493428d7b3dSmrg return FLIP_COMPLETE; 2494428d7b3dSmrg#endif 2495428d7b3dSmrg} 2496428d7b3dSmrg 2497428d7b3dSmrgstatic bool immediate_swap(struct sna *sna, 2498428d7b3dSmrg uint64_t target_msc, 2499428d7b3dSmrg uint64_t divisor, 2500428d7b3dSmrg DrawablePtr draw, 2501428d7b3dSmrg xf86CrtcPtr crtc, 2502428d7b3dSmrg uint64_t *current_msc) 2503428d7b3dSmrg{ 2504428d7b3dSmrg if (divisor == 0) { 2505428d7b3dSmrg *current_msc = -1; 2506428d7b3dSmrg 2507428d7b3dSmrg if (sna->flags & SNA_NO_WAIT) { 2508428d7b3dSmrg DBG(("%s: yes, waits are disabled\n", __FUNCTION__)); 2509428d7b3dSmrg return true; 2510428d7b3dSmrg } 2511428d7b3dSmrg 2512428d7b3dSmrg if (target_msc) 2513428d7b3dSmrg *current_msc = get_current_msc(sna, draw, crtc); 2514428d7b3dSmrg 2515428d7b3dSmrg DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n", 2516428d7b3dSmrg __FUNCTION__, (long)*current_msc, (long)target_msc, 2517428d7b3dSmrg (*current_msc >= target_msc - 1) ? "yes" : "no")); 2518428d7b3dSmrg return *current_msc >= target_msc - 1; 2519428d7b3dSmrg } 2520428d7b3dSmrg 2521428d7b3dSmrg DBG(("%s: explicit waits requests, divisor=%ld\n", 2522428d7b3dSmrg __FUNCTION__, (long)divisor)); 2523428d7b3dSmrg *current_msc = get_current_msc(sna, draw, crtc); 2524428d7b3dSmrg return false; 2525428d7b3dSmrg} 2526428d7b3dSmrg 2527428d7b3dSmrgstatic bool 2528428d7b3dSmrgsna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, 2529428d7b3dSmrg DRI2BufferPtr front, DRI2BufferPtr back, 2530428d7b3dSmrg CARD64 *target_msc, CARD64 divisor, CARD64 remainder, 2531428d7b3dSmrg DRI2SwapEventPtr func, void *data) 2532428d7b3dSmrg{ 2533428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 2534428d7b3dSmrg struct sna_dri2_event *info; 2535428d7b3dSmrg uint64_t current_msc; 2536428d7b3dSmrg 2537428d7b3dSmrg if (immediate_swap(sna, *target_msc, divisor, draw, crtc, ¤t_msc)) { 2538428d7b3dSmrg int type; 2539428d7b3dSmrg 2540428d7b3dSmrg info = sna->dri2.flip_pending; 2541428d7b3dSmrg DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n", 2542428d7b3dSmrg __FUNCTION__, sna_crtc_to_pipe(crtc), 2543428d7b3dSmrg info != NULL, info ? info->mode : 0, 2544428d7b3dSmrg info && info->draw == draw)); 2545428d7b3dSmrg 2546428d7b3dSmrg if (info && info->draw == draw) { 2547428d7b3dSmrg assert(info->type != FLIP); 2548428d7b3dSmrg assert(info->front == front); 2549428d7b3dSmrg if (info->back != back) { 2550428d7b3dSmrg _sna_dri2_destroy_buffer(sna, info->back); 2551428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2552428d7b3dSmrg } 2553428d7b3dSmrg if (info->mode || current_msc >= *target_msc) { 2554428d7b3dSmrg DBG(("%s: executing xchg of pending flip\n", 2555428d7b3dSmrg __FUNCTION__)); 2556428d7b3dSmrg sna_dri2_xchg(draw, front, back); 2557428d7b3dSmrg info->mode = type = FLIP_COMPLETE; 2558428d7b3dSmrg goto new_back; 2559428d7b3dSmrg } else { 2560428d7b3dSmrg DBG(("%s: chaining flip\n", __FUNCTION__)); 2561428d7b3dSmrg type = FLIP_THROTTLE; 2562428d7b3dSmrg if (xorg_can_triple_buffer()) 2563428d7b3dSmrg info->mode = -type; 2564428d7b3dSmrg else 2565428d7b3dSmrg info->mode = -FLIP_COMPLETE; 2566428d7b3dSmrg goto out; 2567428d7b3dSmrg } 2568428d7b3dSmrg } 2569428d7b3dSmrg 2570428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 2571428d7b3dSmrg if (info == NULL) 2572428d7b3dSmrg return false; 2573428d7b3dSmrg 2574428d7b3dSmrg assert(info->crtc == crtc); 2575428d7b3dSmrg info->event_complete = func; 2576428d7b3dSmrg info->event_data = data; 2577428d7b3dSmrg 2578428d7b3dSmrg info->front = sna_dri2_reference_buffer(front); 2579428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2580428d7b3dSmrg 2581428d7b3dSmrg if (sna->dri2.flip_pending) { 2582428d7b3dSmrg /* We need to first wait (one vblank) for the 2583428d7b3dSmrg * async flips to complete before this client 2584428d7b3dSmrg * can take over. 2585428d7b3dSmrg */ 2586428d7b3dSmrg DBG(("%s: queueing flip after pending completion\n", 2587428d7b3dSmrg __FUNCTION__)); 2588428d7b3dSmrg info->type = type = FLIP; 2589428d7b3dSmrg sna->dri2.flip_pending = info; 2590428d7b3dSmrg assert(info->queued); 2591428d7b3dSmrg current_msc++; 2592428d7b3dSmrg } else { 2593428d7b3dSmrg info->type = type = use_triple_buffer(sna, client, *target_msc == 0); 2594428d7b3dSmrg if (!sna_dri2_flip(info)) { 2595428d7b3dSmrg DBG(("%s: flip failed, falling back\n", __FUNCTION__)); 2596428d7b3dSmrg sna_dri2_event_free(info); 2597428d7b3dSmrg return false; 2598428d7b3dSmrg } 2599428d7b3dSmrg } 2600428d7b3dSmrg 2601428d7b3dSmrg swap_limit(draw, 1 + (type == FLIP_THROTTLE)); 2602428d7b3dSmrg if (type >= FLIP_COMPLETE) { 2603428d7b3dSmrgnew_back: 2604428d7b3dSmrg if (!xorg_can_triple_buffer()) 2605428d7b3dSmrg sna_dri2_get_back(sna, draw, back, info); 2606428d7b3dSmrg DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); 2607428d7b3dSmrg frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE); 2608428d7b3dSmrg if (info->type == FLIP_ASYNC) 2609428d7b3dSmrg sna_dri2_event_free(info); 2610428d7b3dSmrg } 2611428d7b3dSmrgout: 2612428d7b3dSmrg DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1)); 2613428d7b3dSmrg *target_msc = current_msc + 1; 2614428d7b3dSmrg return true; 2615428d7b3dSmrg } 2616428d7b3dSmrg 2617428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 2618428d7b3dSmrg if (info == NULL) 2619428d7b3dSmrg return false; 2620428d7b3dSmrg 2621428d7b3dSmrg assert(info->crtc == crtc); 2622428d7b3dSmrg info->event_complete = func; 2623428d7b3dSmrg info->event_data = data; 2624428d7b3dSmrg info->type = FLIP; 2625428d7b3dSmrg 2626428d7b3dSmrg info->front = sna_dri2_reference_buffer(front); 2627428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2628428d7b3dSmrg 2629428d7b3dSmrg /* 2630428d7b3dSmrg * If divisor is zero, or current_msc is smaller than target_msc 2631428d7b3dSmrg * we just need to make sure target_msc passes before initiating 2632428d7b3dSmrg * the swap. 2633428d7b3dSmrg */ 2634428d7b3dSmrg if (divisor && current_msc >= *target_msc) { 2635428d7b3dSmrg DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n", 2636428d7b3dSmrg __FUNCTION__, 2637428d7b3dSmrg (long long)current_msc, 2638428d7b3dSmrg (long long)*target_msc, 2639428d7b3dSmrg (long long)divisor, 2640428d7b3dSmrg (long long)remainder)); 2641428d7b3dSmrg 2642428d7b3dSmrg *target_msc = current_msc + remainder - current_msc % divisor; 2643428d7b3dSmrg if (*target_msc <= current_msc) 2644428d7b3dSmrg *target_msc += divisor; 2645428d7b3dSmrg } 2646428d7b3dSmrg 2647428d7b3dSmrg if (*target_msc <= current_msc + 1) { 2648428d7b3dSmrg if (!sna_dri2_flip(info)) { 2649428d7b3dSmrg sna_dri2_event_free(info); 2650428d7b3dSmrg return false; 2651428d7b3dSmrg } 2652428d7b3dSmrg *target_msc = current_msc + 1; 2653428d7b3dSmrg } else { 2654428d7b3dSmrg union drm_wait_vblank vbl; 2655428d7b3dSmrg 2656428d7b3dSmrg VG_CLEAR(vbl); 2657428d7b3dSmrg 2658428d7b3dSmrg vbl.request.type = 2659428d7b3dSmrg DRM_VBLANK_ABSOLUTE | 2660428d7b3dSmrg DRM_VBLANK_EVENT; 2661428d7b3dSmrg 2662428d7b3dSmrg /* Account for 1 frame extra pageflip delay */ 2663428d7b3dSmrg vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1); 2664428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2665428d7b3dSmrg 2666428d7b3dSmrg info->queued = true; 2667428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, info->pipe)) { 2668428d7b3dSmrg sna_dri2_event_free(info); 2669428d7b3dSmrg return false; 2670428d7b3dSmrg } 2671428d7b3dSmrg } 2672428d7b3dSmrg 2673428d7b3dSmrg DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc)); 2674428d7b3dSmrg swap_limit(draw, 1); 2675428d7b3dSmrg return true; 2676428d7b3dSmrg} 2677428d7b3dSmrg 2678428d7b3dSmrgstatic bool 2679428d7b3dSmrgsna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, 2680428d7b3dSmrg DRI2BufferPtr front, DRI2BufferPtr back, 2681428d7b3dSmrg CARD64 *target_msc, CARD64 divisor, CARD64 remainder, 2682428d7b3dSmrg DRI2SwapEventPtr func, void *data) 2683428d7b3dSmrg{ 2684428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 2685428d7b3dSmrg uint64_t current_msc; 2686428d7b3dSmrg bool sync, event; 2687428d7b3dSmrg 2688428d7b3dSmrg if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, ¤t_msc)) 2689428d7b3dSmrg return false; 2690428d7b3dSmrg 2691428d7b3dSmrg sync = current_msc < *target_msc; 2692428d7b3dSmrg event = dri2_chain(draw) == NULL; 2693428d7b3dSmrg if (!sync || event) { 2694428d7b3dSmrg DBG(("%s: performing immediate xchg on pipe %d\n", 2695428d7b3dSmrg __FUNCTION__, sna_crtc_to_pipe(crtc))); 2696428d7b3dSmrg sna_dri2_xchg(draw, front, back); 2697428d7b3dSmrg } 2698428d7b3dSmrg if (sync) { 2699428d7b3dSmrg struct sna_dri2_event *info; 2700428d7b3dSmrg 2701428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 2702428d7b3dSmrg if (!info) 2703428d7b3dSmrg goto complete; 2704428d7b3dSmrg 2705428d7b3dSmrg info->event_complete = func; 2706428d7b3dSmrg info->event_data = data; 2707428d7b3dSmrg 2708428d7b3dSmrg info->front = sna_dri2_reference_buffer(front); 2709428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2710428d7b3dSmrg info->type = SWAP_THROTTLE; 2711428d7b3dSmrg 2712428d7b3dSmrg if (event) { 2713428d7b3dSmrg union drm_wait_vblank vbl; 2714428d7b3dSmrg 2715428d7b3dSmrg VG_CLEAR(vbl); 2716428d7b3dSmrg vbl.request.type = 2717428d7b3dSmrg DRM_VBLANK_RELATIVE | 2718428d7b3dSmrg DRM_VBLANK_EVENT; 2719428d7b3dSmrg vbl.request.sequence = 1; 2720428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2721428d7b3dSmrg 2722428d7b3dSmrg info->queued = true; 2723428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, info->pipe)) { 2724428d7b3dSmrg sna_dri2_event_free(info); 2725428d7b3dSmrg goto complete; 2726428d7b3dSmrg } 2727428d7b3dSmrg 2728428d7b3dSmrg swap_limit(draw, 2); 2729428d7b3dSmrg } 2730428d7b3dSmrg } else { 2731428d7b3dSmrgcomplete: 2732428d7b3dSmrg fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data); 2733428d7b3dSmrg } 2734428d7b3dSmrg 2735428d7b3dSmrg *target_msc = current_msc + 1; 2736428d7b3dSmrg return true; 2737428d7b3dSmrg} 2738428d7b3dSmrg 2739428d7b3dSmrgstatic bool 2740428d7b3dSmrgsna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, 2741428d7b3dSmrg DRI2BufferPtr front, DRI2BufferPtr back, 2742428d7b3dSmrg CARD64 *target_msc, CARD64 divisor, CARD64 remainder, 2743428d7b3dSmrg DRI2SwapEventPtr func, void *data) 2744428d7b3dSmrg{ 2745428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 2746428d7b3dSmrg uint64_t current_msc; 2747428d7b3dSmrg bool sync, event; 2748428d7b3dSmrg 2749428d7b3dSmrg if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, ¤t_msc)) 2750428d7b3dSmrg return false; 2751428d7b3dSmrg 2752428d7b3dSmrg sync = current_msc < *target_msc; 2753428d7b3dSmrg event = dri2_chain(draw) == NULL; 2754428d7b3dSmrg if (!sync || event) { 2755428d7b3dSmrg DBG(("%s: performing immediate xchg only on pipe %d\n", 2756428d7b3dSmrg __FUNCTION__, sna_crtc_to_pipe(crtc))); 2757428d7b3dSmrg sna_dri2_xchg_crtc(sna, draw, crtc, front, back); 2758428d7b3dSmrg } 2759428d7b3dSmrg if (sync) { 2760428d7b3dSmrg struct sna_dri2_event *info; 2761428d7b3dSmrg 2762428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 2763428d7b3dSmrg if (!info) 2764428d7b3dSmrg goto complete; 2765428d7b3dSmrg 2766428d7b3dSmrg info->event_complete = func; 2767428d7b3dSmrg info->event_data = data; 2768428d7b3dSmrg 2769428d7b3dSmrg info->front = sna_dri2_reference_buffer(front); 2770428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2771428d7b3dSmrg info->type = SWAP_THROTTLE; 2772428d7b3dSmrg 2773428d7b3dSmrg if (event) { 2774428d7b3dSmrg union drm_wait_vblank vbl; 2775428d7b3dSmrg 2776428d7b3dSmrg VG_CLEAR(vbl); 2777428d7b3dSmrg vbl.request.type = 2778428d7b3dSmrg DRM_VBLANK_RELATIVE | 2779428d7b3dSmrg DRM_VBLANK_EVENT; 2780428d7b3dSmrg vbl.request.sequence = 1; 2781428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2782428d7b3dSmrg 2783428d7b3dSmrg info->queued = true; 2784428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, info->pipe)) { 2785428d7b3dSmrg sna_dri2_event_free(info); 2786428d7b3dSmrg goto complete; 2787428d7b3dSmrg } 2788428d7b3dSmrg 2789428d7b3dSmrg swap_limit(draw, 2); 2790428d7b3dSmrg } 2791428d7b3dSmrg } else { 2792428d7b3dSmrgcomplete: 2793428d7b3dSmrg fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data); 2794428d7b3dSmrg } 2795428d7b3dSmrg 2796428d7b3dSmrg *target_msc = current_msc + 1; 2797428d7b3dSmrg return true; 2798428d7b3dSmrg} 2799428d7b3dSmrg 2800428d7b3dSmrgstatic bool has_pending_events(struct sna *sna) 2801428d7b3dSmrg{ 2802428d7b3dSmrg struct pollfd pfd; 2803428d7b3dSmrg pfd.fd = sna->kgem.fd; 2804428d7b3dSmrg pfd.events = POLLIN; 2805428d7b3dSmrg return poll(&pfd, 1, 0) == 1; 2806428d7b3dSmrg} 2807428d7b3dSmrg 2808428d7b3dSmrg/* 2809428d7b3dSmrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 2810428d7b3dSmrg * appropriate frame. 2811428d7b3dSmrg * 2812428d7b3dSmrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 2813428d7b3dSmrg * the vblank requested can simply be the last queued swap frame + the swap 2814428d7b3dSmrg * interval for the drawable. 2815428d7b3dSmrg * 2816428d7b3dSmrg * In the case of a page flip, we request an event for the last queued swap 2817428d7b3dSmrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 2818428d7b3dSmrg * immediately following the received event. 2819428d7b3dSmrg * 2820428d7b3dSmrg * The client will be blocked if it tries to perform further GL commands 2821428d7b3dSmrg * after queueing a swap, though in the Intel case after queueing a flip, the 2822428d7b3dSmrg * client is free to queue more commands; they'll block in the kernel if 2823428d7b3dSmrg * they access buffers busy with the flip. 2824428d7b3dSmrg * 2825428d7b3dSmrg * When the swap is complete, the driver should call into the server so it 2826428d7b3dSmrg * can send any swap complete events that have been requested. 2827428d7b3dSmrg */ 2828428d7b3dSmrgstatic int 2829428d7b3dSmrgsna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 2830428d7b3dSmrg DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 2831428d7b3dSmrg CARD64 remainder, DRI2SwapEventPtr func, void *data) 2832428d7b3dSmrg{ 2833428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 2834428d7b3dSmrg union drm_wait_vblank vbl; 2835428d7b3dSmrg xf86CrtcPtr crtc = NULL; 2836428d7b3dSmrg struct sna_dri2_event *info = NULL; 2837428d7b3dSmrg int type = DRI2_EXCHANGE_COMPLETE; 2838428d7b3dSmrg CARD64 current_msc; 2839428d7b3dSmrg 2840428d7b3dSmrg DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n", 2841428d7b3dSmrg __FUNCTION__, 2842428d7b3dSmrg (long)draw->id, draw->width, draw->height, 2843428d7b3dSmrg get_drawable_pixmap(draw)->drawable.serialNumber, 2844428d7b3dSmrg get_drawable_pixmap(draw)->drawable.width, 2845428d7b3dSmrg get_drawable_pixmap(draw)->drawable.height, 2846428d7b3dSmrg get_private(back)->bo->handle, 2847428d7b3dSmrg get_private(back)->refcnt, 2848428d7b3dSmrg get_private(back)->bo->refcnt, 2849428d7b3dSmrg get_private(back)->bo->flush, 2850428d7b3dSmrg get_private(front)->bo->handle, 2851428d7b3dSmrg get_private(front)->refcnt, 2852428d7b3dSmrg get_private(front)->bo->refcnt, 2853428d7b3dSmrg get_private(front)->bo->flush)); 2854428d7b3dSmrg 2855428d7b3dSmrg DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n", 2856428d7b3dSmrg __FUNCTION__, 2857428d7b3dSmrg (long long)*target_msc, 2858428d7b3dSmrg (long long)divisor, 2859428d7b3dSmrg (long long)remainder)); 2860428d7b3dSmrg 2861428d7b3dSmrg assert(get_private(front)->refcnt); 2862428d7b3dSmrg assert(get_private(back)->refcnt); 2863428d7b3dSmrg 2864428d7b3dSmrg assert(get_private(front)->bo->refcnt); 2865428d7b3dSmrg assert(get_private(back)->bo->refcnt); 2866428d7b3dSmrg 2867428d7b3dSmrg if (get_private(front)->pixmap != get_drawable_pixmap(draw)) { 2868428d7b3dSmrg DBG(("%s: decoupled DRI2 front pixmap=%ld, actual pixmap=%ld\n", 2869428d7b3dSmrg __FUNCTION__, 2870428d7b3dSmrg get_private(front)->pixmap->drawable.serialNumber, 2871428d7b3dSmrg get_drawable_pixmap(draw)->drawable.serialNumber)); 2872428d7b3dSmrg goto skip; 2873428d7b3dSmrg } 2874428d7b3dSmrg 2875428d7b3dSmrg if (get_private(back)->stale) { 2876428d7b3dSmrg DBG(("%s: stale back buffer\n", __FUNCTION__)); 2877428d7b3dSmrg goto skip; 2878428d7b3dSmrg } 2879428d7b3dSmrg 2880428d7b3dSmrg assert(sna_pixmap_from_drawable(draw)->flush); 2881428d7b3dSmrg 2882428d7b3dSmrg if (draw->type != DRAWABLE_PIXMAP) { 2883428d7b3dSmrg WindowPtr win = (WindowPtr)draw; 2884428d7b3dSmrg struct dri2_window *priv = dri2_window(win); 2885428d7b3dSmrg if (priv->front) { 2886428d7b3dSmrg assert(front == priv->front); 2887428d7b3dSmrg assert(get_private(priv->front)->refcnt > 1); 2888428d7b3dSmrg get_private(priv->front)->refcnt--; 2889428d7b3dSmrg priv->front = NULL; 2890428d7b3dSmrg } 2891428d7b3dSmrg if (win->clipList.extents.x2 <= win->clipList.extents.x1 || 2892428d7b3dSmrg win->clipList.extents.y2 <= win->clipList.extents.y1) { 2893428d7b3dSmrg DBG(("%s: window clipped (%d, %d), (%d, %d)\n", 2894428d7b3dSmrg __FUNCTION__, 2895428d7b3dSmrg win->clipList.extents.x1, 2896428d7b3dSmrg win->clipList.extents.y1, 2897428d7b3dSmrg win->clipList.extents.x2, 2898428d7b3dSmrg win->clipList.extents.y2)); 2899428d7b3dSmrg goto skip; 2900428d7b3dSmrg } 2901428d7b3dSmrg } 2902428d7b3dSmrg 2903428d7b3dSmrg /* Drawable not displayed... just complete the swap */ 2904428d7b3dSmrg if ((sna->flags & SNA_NO_WAIT) == 0) 2905428d7b3dSmrg crtc = sna_dri2_get_crtc(draw); 2906428d7b3dSmrg if (crtc == NULL) { 2907428d7b3dSmrg DBG(("%s: off-screen, immediate update\n", __FUNCTION__)); 2908428d7b3dSmrg goto blit; 2909428d7b3dSmrg } 2910428d7b3dSmrg 2911428d7b3dSmrg assert(draw->type != DRAWABLE_PIXMAP); 2912428d7b3dSmrg 2913428d7b3dSmrg while (dri2_chain(draw) && has_pending_events(sna)) { 2914428d7b3dSmrg DBG(("%s: flushing pending events\n", __FUNCTION__)); 2915428d7b3dSmrg sna_mode_wakeup(sna); 2916428d7b3dSmrg } 2917428d7b3dSmrg 2918428d7b3dSmrg if (can_xchg(sna, draw, front, back) && 2919428d7b3dSmrg sna_dri2_schedule_xchg(client, draw, crtc, front, back, 2920428d7b3dSmrg target_msc, divisor, remainder, 2921428d7b3dSmrg func, data)) 2922428d7b3dSmrg return TRUE; 2923428d7b3dSmrg 2924428d7b3dSmrg if (can_xchg_crtc(sna, draw, front, back, crtc) && 2925428d7b3dSmrg sna_dri2_schedule_xchg_crtc(client, draw, crtc, front, back, 2926428d7b3dSmrg target_msc, divisor, remainder, 2927428d7b3dSmrg func, data)) 2928428d7b3dSmrg return TRUE; 2929428d7b3dSmrg 2930428d7b3dSmrg if (can_flip(sna, draw, front, back, crtc) && 2931428d7b3dSmrg sna_dri2_schedule_flip(client, draw, crtc, front, back, 2932428d7b3dSmrg target_msc, divisor, remainder, 2933428d7b3dSmrg func, data)) 2934428d7b3dSmrg return TRUE; 2935428d7b3dSmrg 2936428d7b3dSmrg VG_CLEAR(vbl); 2937428d7b3dSmrg 2938428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 2939428d7b3dSmrg if (!info) 2940428d7b3dSmrg goto blit; 2941428d7b3dSmrg 2942428d7b3dSmrg assert(info->crtc == crtc); 2943428d7b3dSmrg info->event_complete = func; 2944428d7b3dSmrg info->event_data = data; 2945428d7b3dSmrg 2946428d7b3dSmrg info->front = sna_dri2_reference_buffer(front); 2947428d7b3dSmrg info->back = sna_dri2_reference_buffer(back); 2948428d7b3dSmrg 2949428d7b3dSmrg if (immediate_swap(sna, *target_msc, divisor, draw, crtc, ¤t_msc)) { 2950428d7b3dSmrg bool sync = current_msc < *target_msc; 2951428d7b3dSmrg if (!sna_dri2_immediate_blit(sna, info, sync, true)) 2952428d7b3dSmrg sna_dri2_event_free(info); 2953428d7b3dSmrg *target_msc = current_msc + sync; 2954428d7b3dSmrg return TRUE; 2955428d7b3dSmrg } 2956428d7b3dSmrg 2957428d7b3dSmrg vbl.request.type = 2958428d7b3dSmrg DRM_VBLANK_ABSOLUTE | 2959428d7b3dSmrg DRM_VBLANK_EVENT; 2960428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 2961428d7b3dSmrg 2962428d7b3dSmrg /* 2963428d7b3dSmrg * If divisor is zero, or current_msc is smaller than target_msc 2964428d7b3dSmrg * we just need to make sure target_msc passes before initiating 2965428d7b3dSmrg * the swap. 2966428d7b3dSmrg */ 2967428d7b3dSmrg info->type = SWAP; 2968428d7b3dSmrg info->queued = true; 2969428d7b3dSmrg if (divisor && current_msc >= *target_msc) { 2970428d7b3dSmrg DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n", 2971428d7b3dSmrg __FUNCTION__, 2972428d7b3dSmrg (long long)current_msc, 2973428d7b3dSmrg (long long)*target_msc, 2974428d7b3dSmrg (long long)divisor, 2975428d7b3dSmrg (long long)remainder)); 2976428d7b3dSmrg 2977428d7b3dSmrg *target_msc = current_msc + remainder - current_msc % divisor; 2978428d7b3dSmrg if (*target_msc <= current_msc) 2979428d7b3dSmrg *target_msc += divisor; 2980428d7b3dSmrg } 2981428d7b3dSmrg vbl.request.sequence = draw_target_seq(draw, *target_msc - 1); 2982428d7b3dSmrg if (*target_msc <= current_msc + 1) { 2983428d7b3dSmrg DBG(("%s: performing blit before queueing\n", __FUNCTION__)); 2984428d7b3dSmrg assert(info->queued); 2985428d7b3dSmrg info->bo = __sna_dri2_copy_region(sna, draw, NULL, 2986428d7b3dSmrg back, front, 2987428d7b3dSmrg true); 2988428d7b3dSmrg info->type = SWAP_WAIT; 2989428d7b3dSmrg 2990428d7b3dSmrg vbl.request.type = 2991428d7b3dSmrg DRM_VBLANK_RELATIVE | 2992428d7b3dSmrg DRM_VBLANK_EVENT; 2993428d7b3dSmrg vbl.request.sequence = 1; 2994428d7b3dSmrg *target_msc = current_msc + 1; 2995428d7b3dSmrg } 2996428d7b3dSmrg 2997428d7b3dSmrg assert(info->queued); 2998428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, info->pipe)) 2999428d7b3dSmrg goto blit; 3000428d7b3dSmrg 3001428d7b3dSmrg DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc)); 3002428d7b3dSmrg swap_limit(draw, 1 + (info->type == SWAP_WAIT)); 3003428d7b3dSmrg return TRUE; 3004428d7b3dSmrg 3005428d7b3dSmrgblit: 3006428d7b3dSmrg DBG(("%s -- blit\n", __FUNCTION__)); 3007428d7b3dSmrg if (info) 3008428d7b3dSmrg sna_dri2_event_free(info); 3009428d7b3dSmrg if (can_xchg(sna, draw, front, back)) { 3010428d7b3dSmrg sna_dri2_xchg(draw, front, back); 3011428d7b3dSmrg } else { 3012428d7b3dSmrg __sna_dri2_copy_region(sna, draw, NULL, back, front, false); 3013428d7b3dSmrg type = DRI2_BLIT_COMPLETE; 3014428d7b3dSmrg } 3015428d7b3dSmrgskip: 3016428d7b3dSmrg DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__)); 3017428d7b3dSmrg if (crtc == NULL) 3018428d7b3dSmrg crtc = sna_mode_first_crtc(sna); 3019428d7b3dSmrg fake_swap_complete(sna, client, draw, crtc, type, func, data); 3020428d7b3dSmrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 3021428d7b3dSmrg return TRUE; 3022428d7b3dSmrg} 3023428d7b3dSmrg 3024428d7b3dSmrg/* 3025428d7b3dSmrg * Get current frame count and frame count timestamp, based on drawable's 3026428d7b3dSmrg * crtc. 3027428d7b3dSmrg */ 3028428d7b3dSmrgstatic int 3029428d7b3dSmrgsna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 3030428d7b3dSmrg{ 3031428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 3032428d7b3dSmrg xf86CrtcPtr crtc = sna_dri2_get_crtc(draw); 3033428d7b3dSmrg const struct ust_msc *swap; 3034428d7b3dSmrg 3035428d7b3dSmrg DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id, 3036428d7b3dSmrg crtc ? sna_crtc_to_pipe(crtc) : -1)); 3037428d7b3dSmrg 3038428d7b3dSmrg if (crtc != NULL) { 3039428d7b3dSmrg union drm_wait_vblank vbl; 3040428d7b3dSmrg 3041428d7b3dSmrg VG_CLEAR(vbl); 3042428d7b3dSmrg vbl.request.type = _DRM_VBLANK_RELATIVE; 3043428d7b3dSmrg vbl.request.sequence = 0; 3044428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0) 3045428d7b3dSmrg sna_crtc_record_vblank(crtc, &vbl); 3046428d7b3dSmrg } else 3047428d7b3dSmrg /* Drawable not displayed, make up a *monotonic* value */ 3048428d7b3dSmrg crtc = sna_mode_first_crtc(sna); 3049428d7b3dSmrg 3050428d7b3dSmrg swap = sna_crtc_last_swap(crtc); 3051428d7b3dSmrg *msc = draw_current_msc(draw, crtc, swap->msc); 3052428d7b3dSmrg *ust = ust64(swap->tv_sec, swap->tv_usec); 3053428d7b3dSmrg DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__, 3054428d7b3dSmrg (long long)*msc, (long long)*ust)); 3055428d7b3dSmrg return TRUE; 3056428d7b3dSmrg} 3057428d7b3dSmrg 3058428d7b3dSmrg/* 3059428d7b3dSmrg * Request a DRM event when the requested conditions will be satisfied. 3060428d7b3dSmrg * 3061428d7b3dSmrg * We need to handle the event and ask the server to wake up the client when 3062428d7b3dSmrg * we receive it. 3063428d7b3dSmrg */ 3064428d7b3dSmrgstatic int 3065428d7b3dSmrgsna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 3066428d7b3dSmrg CARD64 divisor, CARD64 remainder) 3067428d7b3dSmrg{ 3068428d7b3dSmrg struct sna *sna = to_sna_from_drawable(draw); 3069428d7b3dSmrg struct sna_dri2_event *info = NULL; 3070428d7b3dSmrg xf86CrtcPtr crtc; 3071428d7b3dSmrg CARD64 current_msc; 3072428d7b3dSmrg union drm_wait_vblank vbl; 3073428d7b3dSmrg const struct ust_msc *swap; 3074428d7b3dSmrg int pipe; 3075428d7b3dSmrg 3076428d7b3dSmrg crtc = sna_dri2_get_crtc(draw); 3077428d7b3dSmrg DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n", 3078428d7b3dSmrg __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1, 3079428d7b3dSmrg (long long)target_msc, 3080428d7b3dSmrg (long long)divisor, 3081428d7b3dSmrg (long long)remainder)); 3082428d7b3dSmrg 3083428d7b3dSmrg /* Drawable not visible, return immediately */ 3084428d7b3dSmrg if (crtc == NULL) 3085428d7b3dSmrg goto out_complete; 3086428d7b3dSmrg 3087428d7b3dSmrg pipe = sna_crtc_to_pipe(crtc); 3088428d7b3dSmrg 3089428d7b3dSmrg VG_CLEAR(vbl); 3090428d7b3dSmrg 3091428d7b3dSmrg /* Get current count */ 3092428d7b3dSmrg vbl.request.type = _DRM_VBLANK_RELATIVE; 3093428d7b3dSmrg vbl.request.sequence = 0; 3094428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, pipe)) 3095428d7b3dSmrg goto out_complete; 3096428d7b3dSmrg 3097428d7b3dSmrg current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl)); 3098428d7b3dSmrg 3099428d7b3dSmrg /* If target_msc already reached or passed, set it to 3100428d7b3dSmrg * current_msc to ensure we return a reasonable value back 3101428d7b3dSmrg * to the caller. This keeps the client from continually 3102428d7b3dSmrg * sending us MSC targets from the past by forcibly updating 3103428d7b3dSmrg * their count on this call. 3104428d7b3dSmrg */ 3105428d7b3dSmrg if (divisor == 0 && current_msc >= target_msc) 3106428d7b3dSmrg goto out_complete; 3107428d7b3dSmrg 3108428d7b3dSmrg info = sna_dri2_add_event(sna, draw, client); 3109428d7b3dSmrg if (!info) 3110428d7b3dSmrg goto out_complete; 3111428d7b3dSmrg 3112428d7b3dSmrg assert(info->crtc == crtc); 3113428d7b3dSmrg info->type = WAITMSC; 3114428d7b3dSmrg 3115428d7b3dSmrg vbl.request.signal = (uintptr_t)info; 3116428d7b3dSmrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 3117428d7b3dSmrg /* 3118428d7b3dSmrg * If divisor is zero, or current_msc is smaller than target_msc, 3119428d7b3dSmrg * we just need to make sure target_msc passes before waking up the 3120428d7b3dSmrg * client. Otherwise, compute the next msc to match divisor/remainder. 3121428d7b3dSmrg */ 3122428d7b3dSmrg if (divisor && current_msc >= target_msc) { 3123428d7b3dSmrg DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n", 3124428d7b3dSmrg __FUNCTION__, 3125428d7b3dSmrg (long long)current_msc, 3126428d7b3dSmrg (long long)target_msc, 3127428d7b3dSmrg (long long)divisor, 3128428d7b3dSmrg (long long)remainder)); 3129428d7b3dSmrg target_msc = current_msc + remainder - current_msc % divisor; 3130428d7b3dSmrg if (target_msc <= current_msc) 3131428d7b3dSmrg target_msc += divisor; 3132428d7b3dSmrg } 3133428d7b3dSmrg vbl.request.sequence = draw_target_seq(draw, target_msc); 3134428d7b3dSmrg 3135428d7b3dSmrg info->queued = true; 3136428d7b3dSmrg if (sna_wait_vblank(sna, &vbl, pipe)) 3137428d7b3dSmrg goto out_free_info; 3138428d7b3dSmrg 3139428d7b3dSmrg DRI2BlockClient(client, draw); 3140428d7b3dSmrg return TRUE; 3141428d7b3dSmrg 3142428d7b3dSmrgout_free_info: 3143428d7b3dSmrg sna_dri2_event_free(info); 3144428d7b3dSmrgout_complete: 3145428d7b3dSmrg if (crtc == NULL) 3146428d7b3dSmrg crtc = sna_mode_first_crtc(sna); 3147428d7b3dSmrg swap = sna_crtc_last_swap(crtc); 3148428d7b3dSmrg DRI2WaitMSCComplete(client, draw, 3149428d7b3dSmrg draw_current_msc(draw, crtc, swap->msc), 3150428d7b3dSmrg swap->tv_sec, swap->tv_usec); 3151428d7b3dSmrg return TRUE; 3152428d7b3dSmrg} 3153428d7b3dSmrg#else 3154428d7b3dSmrgvoid sna_dri2_destroy_window(WindowPtr win) { } 3155428d7b3dSmrgvoid sna_dri2_decouple_window(WindowPtr win) { } 3156428d7b3dSmrg#endif 3157428d7b3dSmrg 3158428d7b3dSmrgstatic bool has_i830_dri(void) 3159428d7b3dSmrg{ 3160428d7b3dSmrg return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 3161428d7b3dSmrg} 3162428d7b3dSmrg 3163428d7b3dSmrgstatic int 3164428d7b3dSmrgnamecmp(const char *s1, const char *s2) 3165428d7b3dSmrg{ 3166428d7b3dSmrg char c1, c2; 3167428d7b3dSmrg 3168428d7b3dSmrg if (!s1 || *s1 == 0) { 3169428d7b3dSmrg if (!s2 || *s2 == 0) 3170428d7b3dSmrg return 0; 3171428d7b3dSmrg else 3172428d7b3dSmrg return 1; 3173428d7b3dSmrg } 3174428d7b3dSmrg 3175428d7b3dSmrg while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 3176428d7b3dSmrg s1++; 3177428d7b3dSmrg 3178428d7b3dSmrg while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 3179428d7b3dSmrg s2++; 3180428d7b3dSmrg 3181428d7b3dSmrg c1 = isupper(*s1) ? tolower(*s1) : *s1; 3182428d7b3dSmrg c2 = isupper(*s2) ? tolower(*s2) : *s2; 3183428d7b3dSmrg while (c1 == c2) { 3184428d7b3dSmrg if (c1 == '\0') 3185428d7b3dSmrg return 0; 3186428d7b3dSmrg 3187428d7b3dSmrg s1++; 3188428d7b3dSmrg while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 3189428d7b3dSmrg s1++; 3190428d7b3dSmrg 3191428d7b3dSmrg s2++; 3192428d7b3dSmrg while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 3193428d7b3dSmrg s2++; 3194428d7b3dSmrg 3195428d7b3dSmrg c1 = isupper(*s1) ? tolower(*s1) : *s1; 3196428d7b3dSmrg c2 = isupper(*s2) ? tolower(*s2) : *s2; 3197428d7b3dSmrg } 3198428d7b3dSmrg 3199428d7b3dSmrg return c1 - c2; 3200428d7b3dSmrg} 3201428d7b3dSmrg 3202428d7b3dSmrgstatic bool is_level(const char **str) 3203428d7b3dSmrg{ 3204428d7b3dSmrg const char *s = *str; 3205428d7b3dSmrg char *end; 3206428d7b3dSmrg unsigned val; 3207428d7b3dSmrg 3208428d7b3dSmrg if (s == NULL || *s == '\0') 3209428d7b3dSmrg return true; 3210428d7b3dSmrg 3211428d7b3dSmrg if (namecmp(s, "on") == 0) 3212428d7b3dSmrg return true; 3213428d7b3dSmrg if (namecmp(s, "true") == 0) 3214428d7b3dSmrg return true; 3215428d7b3dSmrg if (namecmp(s, "yes") == 0) 3216428d7b3dSmrg return true; 3217428d7b3dSmrg 3218428d7b3dSmrg if (namecmp(s, "0") == 0) 3219428d7b3dSmrg return true; 3220428d7b3dSmrg if (namecmp(s, "off") == 0) 3221428d7b3dSmrg return true; 3222428d7b3dSmrg if (namecmp(s, "false") == 0) 3223428d7b3dSmrg return true; 3224428d7b3dSmrg if (namecmp(s, "no") == 0) 3225428d7b3dSmrg return true; 3226428d7b3dSmrg 3227428d7b3dSmrg val = strtoul(s, &end, 0); 3228428d7b3dSmrg if (val && *end == '\0') 3229428d7b3dSmrg return true; 3230428d7b3dSmrg if (val && *end == ':') 3231428d7b3dSmrg *str = end + 1; 3232428d7b3dSmrg return false; 3233428d7b3dSmrg} 3234428d7b3dSmrg 3235428d7b3dSmrgstatic const char *dri_driver_name(struct sna *sna) 3236428d7b3dSmrg{ 3237428d7b3dSmrg const char *s = xf86GetOptValString(sna->Options, OPTION_DRI); 3238428d7b3dSmrg 3239428d7b3dSmrg if (is_level(&s)) { 3240428d7b3dSmrg if (sna->kgem.gen < 030) 3241428d7b3dSmrg return has_i830_dri() ? "i830" : "i915"; 3242428d7b3dSmrg else if (sna->kgem.gen < 040) 3243428d7b3dSmrg return "i915"; 3244428d7b3dSmrg else 3245428d7b3dSmrg return "i965"; 3246428d7b3dSmrg } 3247428d7b3dSmrg 3248428d7b3dSmrg return s; 3249428d7b3dSmrg} 3250428d7b3dSmrg 3251428d7b3dSmrgbool sna_dri2_open(struct sna *sna, ScreenPtr screen) 3252428d7b3dSmrg{ 3253428d7b3dSmrg DRI2InfoRec info; 3254428d7b3dSmrg int major = 1, minor = 0; 3255428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 3256428d7b3dSmrg const char *driverNames[2]; 3257428d7b3dSmrg#endif 3258428d7b3dSmrg 3259428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 3260428d7b3dSmrg 3261428d7b3dSmrg if (wedged(sna)) { 3262428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 3263428d7b3dSmrg "loading DRI2 whilst the GPU is wedged.\n"); 3264428d7b3dSmrg } 3265428d7b3dSmrg 3266428d7b3dSmrg if (xf86LoaderCheckSymbol("DRI2Version")) 3267428d7b3dSmrg DRI2Version(&major, &minor); 3268428d7b3dSmrg 3269428d7b3dSmrg if (minor < 1) { 3270428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 3271428d7b3dSmrg "DRI2 requires DRI2 module version 1.1.0 or later\n"); 3272428d7b3dSmrg return false; 3273428d7b3dSmrg } 3274428d7b3dSmrg 3275428d7b3dSmrg memset(&info, '\0', sizeof(info)); 3276428d7b3dSmrg info.fd = sna->kgem.fd; 3277428d7b3dSmrg info.driverName = dri_driver_name(sna); 3278428d7b3dSmrg info.deviceName = intel_get_client_name(sna->dev); 3279428d7b3dSmrg 3280428d7b3dSmrg DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n", 3281428d7b3dSmrg __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName)); 3282428d7b3dSmrg 3283428d7b3dSmrg#if DRI2INFOREC_VERSION == 2 3284428d7b3dSmrg /* The ABI between 2 and 3 was broken so we could get rid of 3285428d7b3dSmrg * the multi-buffer alloc functions. Make sure we indicate the 3286428d7b3dSmrg * right version so DRI2 can reject us if it's version 3 or above. */ 3287428d7b3dSmrg info.version = 2; 3288428d7b3dSmrg#else 3289428d7b3dSmrg info.version = 3; 3290428d7b3dSmrg#endif 3291428d7b3dSmrg info.CreateBuffer = sna_dri2_create_buffer; 3292428d7b3dSmrg info.DestroyBuffer = sna_dri2_destroy_buffer; 3293428d7b3dSmrg 3294428d7b3dSmrg info.CopyRegion = sna_dri2_copy_region; 3295428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4 3296428d7b3dSmrg info.version = 4; 3297428d7b3dSmrg info.ScheduleSwap = sna_dri2_schedule_swap; 3298428d7b3dSmrg info.GetMSC = sna_dri2_get_msc; 3299428d7b3dSmrg info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc; 3300428d7b3dSmrg info.numDrivers = 2; 3301428d7b3dSmrg info.driverNames = driverNames; 3302428d7b3dSmrg driverNames[0] = info.driverName; 3303428d7b3dSmrg driverNames[1] = info.driverName; 3304428d7b3dSmrg#endif 3305428d7b3dSmrg 3306428d7b3dSmrg#if DRI2INFOREC_VERSION >= 6 3307428d7b3dSmrg if (xorg_can_triple_buffer()) { 3308428d7b3dSmrg info.version = 6; 3309428d7b3dSmrg info.SwapLimitValidate = sna_dri2_swap_limit_validate; 3310428d7b3dSmrg info.ReuseBufferNotify = sna_dri2_reuse_buffer; 3311428d7b3dSmrg } 3312428d7b3dSmrg#endif 3313428d7b3dSmrg 3314428d7b3dSmrg#if USE_ASYNC_SWAP 3315428d7b3dSmrg info.version = 10; 3316428d7b3dSmrg info.scheduleSwap0 = 1; 3317428d7b3dSmrg#endif 3318428d7b3dSmrg 3319428d7b3dSmrg return DRI2ScreenInit(screen, &info); 3320428d7b3dSmrg} 3321428d7b3dSmrg 3322428d7b3dSmrgvoid sna_dri2_close(struct sna *sna, ScreenPtr screen) 3323428d7b3dSmrg{ 3324428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 3325428d7b3dSmrg DRI2CloseScreen(screen); 3326428d7b3dSmrg} 3327