1fda9279dSmrg/* 2fda9279dSmrg * Copyright 2013 Red Hat Inc. 3fda9279dSmrg * 4fda9279dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5fda9279dSmrg * copy of this software and associated documentation files (the "Software"), 6fda9279dSmrg * to deal in the Software without restriction, including without limitation 7fda9279dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8fda9279dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9fda9279dSmrg * Software is furnished to do so, subject to the following conditions: 10fda9279dSmrg * 11fda9279dSmrg * The above copyright notice and this permission notice shall be included in 12fda9279dSmrg * all copies or substantial portions of the Software. 13fda9279dSmrg * 14fda9279dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15fda9279dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16fda9279dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17fda9279dSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18fda9279dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19fda9279dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20fda9279dSmrg * OTHER DEALINGS IN THE SOFTWARE. 21fda9279dSmrg * 22fda9279dSmrg * Authors: Ben Skeggs <bskeggs@redhat.com> 23fda9279dSmrg */ 24fda9279dSmrg 25fda9279dSmrg#include "nouveau_present.h" 2616ee1e9aSmrg#if defined(DRI3) 27fda9279dSmrg#include "nv_include.h" 28fda9279dSmrg#include "xf86drmMode.h" 29fda9279dSmrg 30fda9279dSmrgstruct nouveau_present { 31fda9279dSmrg struct present_screen_info info; 32fda9279dSmrg}; 33fda9279dSmrg 34fda9279dSmrgstatic RRCrtcPtr 35fda9279dSmrgnouveau_present_crtc(WindowPtr window) 36fda9279dSmrg{ 3733adc6acSmrg return randr_crtc_covering_drawable(&window->drawable); 38fda9279dSmrg} 39fda9279dSmrg 40fda9279dSmrgstatic int 41fda9279dSmrgnouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc) 42fda9279dSmrg{ 43fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 44fda9279dSmrg NVPtr pNv = NVPTR(crtc->scrn); 45fda9279dSmrg drmVBlank args; 46fda9279dSmrg int ret; 47fda9279dSmrg 48fda9279dSmrg args.request.type = DRM_VBLANK_RELATIVE; 49fda9279dSmrg args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT; 50fda9279dSmrg args.request.sequence = 0, 51fda9279dSmrg args.request.signal = 0, 52fda9279dSmrg 53fda9279dSmrg ret = drmWaitVBlank(pNv->dev->fd, &args); 54fda9279dSmrg if (ret) { 55fda9279dSmrg *ust = *msc = 0; 56fda9279dSmrg return BadMatch; 57fda9279dSmrg } 58fda9279dSmrg 59fda9279dSmrg *ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec; 60fda9279dSmrg *msc = args.reply.sequence; 61fda9279dSmrg return Success; 62fda9279dSmrg} 63fda9279dSmrg 64fda9279dSmrgstruct nouveau_present_vblank { 65fda9279dSmrg uint64_t msc; 66fda9279dSmrg}; 67fda9279dSmrg 68fda9279dSmrgstatic void 69fda9279dSmrgnouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) 70fda9279dSmrg{ 71fda9279dSmrg struct nouveau_present_vblank *event = priv; 72fda9279dSmrg uint64_t msc; 73fda9279dSmrg 74fda9279dSmrg msc = (event->msc & 0xffffffff00000000ULL) | msc_lo; 75fda9279dSmrg if (msc < event->msc) 76fda9279dSmrg event->msc += 1ULL << 32; 77fda9279dSmrg 78fda9279dSmrg present_event_notify(name, ust, msc); 79fda9279dSmrg} 80fda9279dSmrg 81fda9279dSmrgstatic int 82fda9279dSmrgnouveau_present_vblank_queue(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc) 83fda9279dSmrg{ 84fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 85fda9279dSmrg NVPtr pNv = NVPTR(crtc->scrn); 86fda9279dSmrg drmVBlank args; 87fda9279dSmrg struct nouveau_present_vblank *event; 88fda9279dSmrg void *token; 89fda9279dSmrg int ret; 90fda9279dSmrg 91fda9279dSmrg event = drmmode_event_queue(crtc->scrn, event_id, sizeof(*event), 92fda9279dSmrg nouveau_present_vblank, &token); 93fda9279dSmrg if (!event) 94fda9279dSmrg return BadAlloc; 95fda9279dSmrg 96fda9279dSmrg event->msc = msc; 97fda9279dSmrg 98fda9279dSmrg args.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 99fda9279dSmrg args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT; 100fda9279dSmrg args.request.sequence = msc; 101fda9279dSmrg args.request.signal = (unsigned long)token; 102fda9279dSmrg 103fda9279dSmrg while ((ret = drmWaitVBlank(pNv->dev->fd, &args)) != 0) { 10492405695Smrg if (errno != EBUSY) { 10592405695Smrg xf86DrvMsgVerb(crtc->scrn->scrnIndex, X_WARNING, 4, 10692405695Smrg "PRESENT: Wait for VBlank failed: %s\n", strerror(errno)); 10792405695Smrg drmmode_event_abort(crtc->scrn, event_id, false); 108fda9279dSmrg return BadAlloc; 10992405695Smrg } 11092405695Smrg ret = drmmode_event_flush(crtc->scrn); 11192405695Smrg if (ret < 0) { 11292405695Smrg xf86DrvMsgVerb(crtc->scrn->scrnIndex, X_WARNING, 4, 11392405695Smrg "PRESENT: Event flush failed\n"); 11492405695Smrg drmmode_event_abort(crtc->scrn, event_id, false); 11592405695Smrg return BadAlloc; 11692405695Smrg } 117fda9279dSmrg } 118fda9279dSmrg 119fda9279dSmrg return Success; 120fda9279dSmrg} 121fda9279dSmrg 122fda9279dSmrgstatic void 123fda9279dSmrgnouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc) 124fda9279dSmrg{ 125fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 126fda9279dSmrg drmmode_event_abort(crtc->scrn, event_id, true); 127fda9279dSmrg} 128fda9279dSmrg 129fda9279dSmrgstatic void 130fda9279dSmrgnouveau_present_flush(WindowPtr window) 131fda9279dSmrg{ 132fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 133fda9279dSmrg NVPtr pNv = NVPTR(scrn); 134fda9279dSmrg if (pNv->Flush) 135fda9279dSmrg pNv->Flush(scrn); 136fda9279dSmrg} 137fda9279dSmrg 138fda9279dSmrgstruct nouveau_present_flip { 139fda9279dSmrg uint64_t msc; 140fda9279dSmrg uint32_t old; 141fda9279dSmrg int fd; 142fda9279dSmrg}; 143fda9279dSmrg 144fda9279dSmrgstatic Bool 145fda9279dSmrgnouveau_present_flip_check(RRCrtcPtr rrcrtc, WindowPtr window, 146fda9279dSmrg PixmapPtr pixmap, Bool sync_flip) 147fda9279dSmrg{ 148fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 14992405695Smrg NVPtr pNv = NVPTR(scrn); 150fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 15192405695Smrg struct nouveau_pixmap *priv = nouveau_pixmap(pixmap); 152fda9279dSmrg 15333adc6acSmrg if (!scrn->vtSema || !xf86_crtc_on(crtc) || crtc->rotatedData) 154fda9279dSmrg return FALSE; 155fda9279dSmrg 15692405695Smrg if (!priv) { 15792405695Smrg /* The pixmap may not have had backing for low-memory GPUs, or 15892405695Smrg * if we ran out of VRAM. Make sure it's properly backed for 15992405695Smrg * flipping. 16092405695Smrg */ 16192405695Smrg pNv->exa_force_cp = TRUE; 16292405695Smrg exaMoveInPixmap(pixmap); 16392405695Smrg pNv->exa_force_cp = FALSE; 16492405695Smrg priv = nouveau_pixmap(pixmap); 16592405695Smrg } 16692405695Smrg 16792405695Smrg return priv ? TRUE : FALSE; 168fda9279dSmrg} 169fda9279dSmrg 170fda9279dSmrgstatic void 171fda9279dSmrgnouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) 172fda9279dSmrg{ 173fda9279dSmrg struct nouveau_present_flip *flip = priv; 174fda9279dSmrg uint64_t msc; 175fda9279dSmrg 176fda9279dSmrg msc = (flip->msc & ~0xffffffffULL) | msc_lo; 177fda9279dSmrg if (msc < flip->msc) 178fda9279dSmrg msc += 1ULL << 32; 179fda9279dSmrg 180fda9279dSmrg present_event_notify(name, ust, msc); 181fda9279dSmrg drmModeRmFB(flip->fd, flip->old); 182fda9279dSmrg} 183fda9279dSmrg 184fda9279dSmrgstatic Bool 185fda9279dSmrgnouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync, 186fda9279dSmrg uint64_t target_msc, PixmapPtr pixmap, Bool vsync) 187fda9279dSmrg{ 18816ee1e9aSmrg struct nouveau_pixmap *priv = nouveau_pixmap(pixmap); 189fda9279dSmrg NVPtr pNv = NVPTR(scrn); 190fda9279dSmrg uint32_t next_fb; 191fda9279dSmrg void *token; 192fda9279dSmrg int ret; 193fda9279dSmrg 194fda9279dSmrg ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width, 195fda9279dSmrg pixmap->drawable.height, pixmap->drawable.depth, 196fda9279dSmrg pixmap->drawable.bitsPerPixel, pixmap->devKind, 197fda9279dSmrg priv->bo->handle, &next_fb); 198fda9279dSmrg if (ret == 0) { 199fda9279dSmrg struct nouveau_present_flip *flip = 200fda9279dSmrg drmmode_event_queue(scrn, event_id, sizeof(*flip), 201fda9279dSmrg nouveau_present_flip, &token); 202fda9279dSmrg if (flip) { 203fda9279dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 204fda9279dSmrg int last = 0, i; 205fda9279dSmrg 206fda9279dSmrg drmmode_swap(scrn, next_fb, &flip->old); 207fda9279dSmrg flip->fd = pNv->dev->fd; 208fda9279dSmrg flip->msc = target_msc; 209fda9279dSmrg 210fda9279dSmrg for (i = 0; i < config->num_crtc; i++) { 21133adc6acSmrg if (xf86_crtc_on(config->crtc[i])) 212fda9279dSmrg last = i; 213fda9279dSmrg } 214fda9279dSmrg 215fda9279dSmrg for (i = 0; i < config->num_crtc; i++) { 216fda9279dSmrg int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC; 217fda9279dSmrg int crtc = drmmode_crtc(config->crtc[i]); 218fda9279dSmrg void *user = NULL; 219fda9279dSmrg 22033adc6acSmrg if (!xf86_crtc_on(config->crtc[i])) 221fda9279dSmrg continue; 222fda9279dSmrg 223fda9279dSmrg if (token && ((crtc == sync) || (i == last))) { 224fda9279dSmrg type |= DRM_MODE_PAGE_FLIP_EVENT; 225fda9279dSmrg user = token; 226fda9279dSmrg } 227fda9279dSmrg 228fda9279dSmrg ret = drmModePageFlip(pNv->dev->fd, crtc, 229fda9279dSmrg next_fb, type, user); 230fda9279dSmrg if (ret == 0 && user) { 231fda9279dSmrg token = NULL; 232fda9279dSmrg } 233fda9279dSmrg } 234fda9279dSmrg 235fda9279dSmrg if (token == NULL) { 236fda9279dSmrg return TRUE; 237fda9279dSmrg } 238fda9279dSmrg 239fda9279dSmrg drmmode_swap(scrn, flip->old, &next_fb); 240fda9279dSmrg drmmode_event_abort(scrn, event_id, false); 241fda9279dSmrg } 242fda9279dSmrg 243fda9279dSmrg drmModeRmFB(pNv->dev->fd, next_fb); 244fda9279dSmrg } 245fda9279dSmrg 246fda9279dSmrg return FALSE; 247fda9279dSmrg} 248fda9279dSmrg 249fda9279dSmrgstatic Bool 250fda9279dSmrgnouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id, 251fda9279dSmrg uint64_t target_msc, PixmapPtr pixmap, Bool vsync) 252fda9279dSmrg{ 253fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 254fda9279dSmrg ScrnInfoPtr scrn = crtc->scrn; 255fda9279dSmrg return nouveau_present_flip_exec(scrn, event_id, drmmode_crtc(crtc), 256fda9279dSmrg target_msc, pixmap, vsync); 257fda9279dSmrg} 258fda9279dSmrg 259fda9279dSmrgstatic void 260fda9279dSmrgnouveau_present_flip_stop(ScreenPtr screen, uint64_t event_id) 261fda9279dSmrg{ 262fda9279dSmrg PixmapPtr pixmap = screen->GetScreenPixmap(screen); 263fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 264fda9279dSmrg nouveau_present_flip_exec(scrn, event_id, 0, 0, pixmap, TRUE); 265fda9279dSmrg} 266fda9279dSmrg 267fda9279dSmrgvoid 268fda9279dSmrgnouveau_present_fini(ScreenPtr screen) 269fda9279dSmrg{ 270fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 271fda9279dSmrg NVPtr pNv = NVPTR(scrn); 272fda9279dSmrg if (pNv->present) { 273fda9279dSmrg free(pNv->present); 274fda9279dSmrg pNv->present = NULL; 275fda9279dSmrg } 276fda9279dSmrg} 277fda9279dSmrg 27816ee1e9aSmrgBool 279fda9279dSmrgnouveau_present_init(ScreenPtr screen) 280fda9279dSmrg{ 281fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 282fda9279dSmrg NVPtr pNv = NVPTR(scrn); 283fda9279dSmrg struct nouveau_present *present; 284fda9279dSmrg uint64_t value; 285fda9279dSmrg int ret; 286fda9279dSmrg 287fda9279dSmrg present = pNv->present = calloc(1, sizeof(*present)); 288fda9279dSmrg if (!present) 28916ee1e9aSmrg return FALSE; 290fda9279dSmrg 291fda9279dSmrg present->info.version = PRESENT_SCREEN_INFO_VERSION; 292fda9279dSmrg present->info.get_crtc = nouveau_present_crtc; 293fda9279dSmrg present->info.get_ust_msc = nouveau_present_ust_msc; 294fda9279dSmrg present->info.queue_vblank = nouveau_present_vblank_queue; 295fda9279dSmrg present->info.abort_vblank = nouveau_present_vblank_abort; 296fda9279dSmrg present->info.flush = nouveau_present_flush; 297fda9279dSmrg 298fda9279dSmrg if (pNv->has_pageflip) { 299fda9279dSmrg#ifdef DRM_CAP_ASYNC_PAGE_FLIP 300fda9279dSmrg ret = drmGetCap(pNv->dev->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 301fda9279dSmrg if (ret == 0 && value == 1) 302fda9279dSmrg present->info.capabilities |= PresentCapabilityAsync; 303fda9279dSmrg#endif 304fda9279dSmrg present->info.check_flip = nouveau_present_flip_check; 305fda9279dSmrg present->info.flip = nouveau_present_flip_next; 306fda9279dSmrg present->info.unflip = nouveau_present_flip_stop; 307fda9279dSmrg } 308fda9279dSmrg 309fda9279dSmrg return present_screen_init(screen, &present->info); 310fda9279dSmrg} 311fda9279dSmrg#endif 312