nouveau_present.c revision 16ee1e9a
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{ 37fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 38fda9279dSmrg xf86CrtcPtr crtc; 39fda9279dSmrg 40fda9279dSmrg crtc = nouveau_pick_best_crtc(scrn, FALSE, 41fda9279dSmrg window->drawable.x, 42fda9279dSmrg window->drawable.y, 43fda9279dSmrg window->drawable.width, 44fda9279dSmrg window->drawable.height); 45fda9279dSmrg 46fda9279dSmrg if (!crtc) 47fda9279dSmrg return NULL; 48fda9279dSmrg 49fda9279dSmrg if (crtc->rotatedData) 50fda9279dSmrg return NULL; 51fda9279dSmrg 52fda9279dSmrg return crtc->randr_crtc; 53fda9279dSmrg} 54fda9279dSmrg 55fda9279dSmrgstatic int 56fda9279dSmrgnouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc) 57fda9279dSmrg{ 58fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 59fda9279dSmrg NVPtr pNv = NVPTR(crtc->scrn); 60fda9279dSmrg drmVBlank args; 61fda9279dSmrg int ret; 62fda9279dSmrg 63fda9279dSmrg args.request.type = DRM_VBLANK_RELATIVE; 64fda9279dSmrg args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT; 65fda9279dSmrg args.request.sequence = 0, 66fda9279dSmrg args.request.signal = 0, 67fda9279dSmrg 68fda9279dSmrg ret = drmWaitVBlank(pNv->dev->fd, &args); 69fda9279dSmrg if (ret) { 70fda9279dSmrg *ust = *msc = 0; 71fda9279dSmrg return BadMatch; 72fda9279dSmrg } 73fda9279dSmrg 74fda9279dSmrg *ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec; 75fda9279dSmrg *msc = args.reply.sequence; 76fda9279dSmrg return Success; 77fda9279dSmrg} 78fda9279dSmrg 79fda9279dSmrgstruct nouveau_present_vblank { 80fda9279dSmrg uint64_t msc; 81fda9279dSmrg}; 82fda9279dSmrg 83fda9279dSmrgstatic void 84fda9279dSmrgnouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) 85fda9279dSmrg{ 86fda9279dSmrg struct nouveau_present_vblank *event = priv; 87fda9279dSmrg uint64_t msc; 88fda9279dSmrg 89fda9279dSmrg msc = (event->msc & 0xffffffff00000000ULL) | msc_lo; 90fda9279dSmrg if (msc < event->msc) 91fda9279dSmrg event->msc += 1ULL << 32; 92fda9279dSmrg 93fda9279dSmrg present_event_notify(name, ust, msc); 94fda9279dSmrg} 95fda9279dSmrg 96fda9279dSmrgstatic int 97fda9279dSmrgnouveau_present_vblank_queue(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc) 98fda9279dSmrg{ 99fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 100fda9279dSmrg NVPtr pNv = NVPTR(crtc->scrn); 101fda9279dSmrg drmVBlank args; 102fda9279dSmrg struct nouveau_present_vblank *event; 103fda9279dSmrg void *token; 104fda9279dSmrg int ret; 105fda9279dSmrg 106fda9279dSmrg event = drmmode_event_queue(crtc->scrn, event_id, sizeof(*event), 107fda9279dSmrg nouveau_present_vblank, &token); 108fda9279dSmrg if (!event) 109fda9279dSmrg return BadAlloc; 110fda9279dSmrg 111fda9279dSmrg event->msc = msc; 112fda9279dSmrg 113fda9279dSmrg args.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 114fda9279dSmrg args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT; 115fda9279dSmrg args.request.sequence = msc; 116fda9279dSmrg args.request.signal = (unsigned long)token; 117fda9279dSmrg 118fda9279dSmrg while ((ret = drmWaitVBlank(pNv->dev->fd, &args)) != 0) { 119fda9279dSmrg if (errno != EBUSY || drmmode_event_flush(crtc->scrn) < 0) 120fda9279dSmrg return BadAlloc; 121fda9279dSmrg } 122fda9279dSmrg 123fda9279dSmrg return Success; 124fda9279dSmrg} 125fda9279dSmrg 126fda9279dSmrgstatic void 127fda9279dSmrgnouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc) 128fda9279dSmrg{ 129fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 130fda9279dSmrg drmmode_event_abort(crtc->scrn, event_id, true); 131fda9279dSmrg} 132fda9279dSmrg 133fda9279dSmrgstatic void 134fda9279dSmrgnouveau_present_flush(WindowPtr window) 135fda9279dSmrg{ 136fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 137fda9279dSmrg NVPtr pNv = NVPTR(scrn); 138fda9279dSmrg if (pNv->Flush) 139fda9279dSmrg pNv->Flush(scrn); 140fda9279dSmrg} 141fda9279dSmrg 142fda9279dSmrgstruct nouveau_present_flip { 143fda9279dSmrg uint64_t msc; 144fda9279dSmrg uint32_t old; 145fda9279dSmrg int fd; 146fda9279dSmrg}; 147fda9279dSmrg 148fda9279dSmrgstatic Bool 149fda9279dSmrgnouveau_present_flip_check(RRCrtcPtr rrcrtc, WindowPtr window, 150fda9279dSmrg PixmapPtr pixmap, Bool sync_flip) 151fda9279dSmrg{ 152fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen); 153fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 154fda9279dSmrg 155fda9279dSmrg if (!scrn->vtSema || !crtc->enabled) 156fda9279dSmrg return FALSE; 157fda9279dSmrg 158fda9279dSmrg return TRUE; 159fda9279dSmrg} 160fda9279dSmrg 161fda9279dSmrgstatic void 162fda9279dSmrgnouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo) 163fda9279dSmrg{ 164fda9279dSmrg struct nouveau_present_flip *flip = priv; 165fda9279dSmrg uint64_t msc; 166fda9279dSmrg 167fda9279dSmrg msc = (flip->msc & ~0xffffffffULL) | msc_lo; 168fda9279dSmrg if (msc < flip->msc) 169fda9279dSmrg msc += 1ULL << 32; 170fda9279dSmrg 171fda9279dSmrg present_event_notify(name, ust, msc); 172fda9279dSmrg drmModeRmFB(flip->fd, flip->old); 173fda9279dSmrg} 174fda9279dSmrg 175fda9279dSmrgstatic Bool 176fda9279dSmrgnouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync, 177fda9279dSmrg uint64_t target_msc, PixmapPtr pixmap, Bool vsync) 178fda9279dSmrg{ 17916ee1e9aSmrg struct nouveau_pixmap *priv = nouveau_pixmap(pixmap); 180fda9279dSmrg NVPtr pNv = NVPTR(scrn); 181fda9279dSmrg uint32_t next_fb; 182fda9279dSmrg void *token; 183fda9279dSmrg int ret; 184fda9279dSmrg 185fda9279dSmrg ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width, 186fda9279dSmrg pixmap->drawable.height, pixmap->drawable.depth, 187fda9279dSmrg pixmap->drawable.bitsPerPixel, pixmap->devKind, 188fda9279dSmrg priv->bo->handle, &next_fb); 189fda9279dSmrg if (ret == 0) { 190fda9279dSmrg struct nouveau_present_flip *flip = 191fda9279dSmrg drmmode_event_queue(scrn, event_id, sizeof(*flip), 192fda9279dSmrg nouveau_present_flip, &token); 193fda9279dSmrg if (flip) { 194fda9279dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 195fda9279dSmrg int last = 0, i; 196fda9279dSmrg 197fda9279dSmrg drmmode_swap(scrn, next_fb, &flip->old); 198fda9279dSmrg flip->fd = pNv->dev->fd; 199fda9279dSmrg flip->msc = target_msc; 200fda9279dSmrg 201fda9279dSmrg for (i = 0; i < config->num_crtc; i++) { 202fda9279dSmrg if (config->crtc[i]->enabled) 203fda9279dSmrg last = i; 204fda9279dSmrg } 205fda9279dSmrg 206fda9279dSmrg for (i = 0; i < config->num_crtc; i++) { 207fda9279dSmrg int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC; 208fda9279dSmrg int crtc = drmmode_crtc(config->crtc[i]); 209fda9279dSmrg void *user = NULL; 210fda9279dSmrg 211fda9279dSmrg if (!config->crtc[i]->enabled) 212fda9279dSmrg continue; 213fda9279dSmrg 214fda9279dSmrg if (token && ((crtc == sync) || (i == last))) { 215fda9279dSmrg type |= DRM_MODE_PAGE_FLIP_EVENT; 216fda9279dSmrg user = token; 217fda9279dSmrg } 218fda9279dSmrg 219fda9279dSmrg ret = drmModePageFlip(pNv->dev->fd, crtc, 220fda9279dSmrg next_fb, type, user); 221fda9279dSmrg if (ret == 0 && user) { 222fda9279dSmrg token = NULL; 223fda9279dSmrg } 224fda9279dSmrg } 225fda9279dSmrg 226fda9279dSmrg if (token == NULL) { 227fda9279dSmrg return TRUE; 228fda9279dSmrg } 229fda9279dSmrg 230fda9279dSmrg drmmode_swap(scrn, flip->old, &next_fb); 231fda9279dSmrg drmmode_event_abort(scrn, event_id, false); 232fda9279dSmrg } 233fda9279dSmrg 234fda9279dSmrg drmModeRmFB(pNv->dev->fd, next_fb); 235fda9279dSmrg } 236fda9279dSmrg 237fda9279dSmrg return FALSE; 238fda9279dSmrg} 239fda9279dSmrg 240fda9279dSmrgstatic Bool 241fda9279dSmrgnouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id, 242fda9279dSmrg uint64_t target_msc, PixmapPtr pixmap, Bool vsync) 243fda9279dSmrg{ 244fda9279dSmrg xf86CrtcPtr crtc = rrcrtc->devPrivate; 245fda9279dSmrg ScrnInfoPtr scrn = crtc->scrn; 246fda9279dSmrg return nouveau_present_flip_exec(scrn, event_id, drmmode_crtc(crtc), 247fda9279dSmrg target_msc, pixmap, vsync); 248fda9279dSmrg} 249fda9279dSmrg 250fda9279dSmrgstatic void 251fda9279dSmrgnouveau_present_flip_stop(ScreenPtr screen, uint64_t event_id) 252fda9279dSmrg{ 253fda9279dSmrg PixmapPtr pixmap = screen->GetScreenPixmap(screen); 254fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 255fda9279dSmrg nouveau_present_flip_exec(scrn, event_id, 0, 0, pixmap, TRUE); 256fda9279dSmrg} 257fda9279dSmrg 258fda9279dSmrgvoid 259fda9279dSmrgnouveau_present_fini(ScreenPtr screen) 260fda9279dSmrg{ 261fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 262fda9279dSmrg NVPtr pNv = NVPTR(scrn); 263fda9279dSmrg if (pNv->present) { 264fda9279dSmrg free(pNv->present); 265fda9279dSmrg pNv->present = NULL; 266fda9279dSmrg } 267fda9279dSmrg} 268fda9279dSmrg 26916ee1e9aSmrgBool 270fda9279dSmrgnouveau_present_init(ScreenPtr screen) 271fda9279dSmrg{ 272fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 273fda9279dSmrg NVPtr pNv = NVPTR(scrn); 274fda9279dSmrg struct nouveau_present *present; 275fda9279dSmrg uint64_t value; 276fda9279dSmrg int ret; 277fda9279dSmrg 278fda9279dSmrg present = pNv->present = calloc(1, sizeof(*present)); 279fda9279dSmrg if (!present) 28016ee1e9aSmrg return FALSE; 281fda9279dSmrg 282fda9279dSmrg present->info.version = PRESENT_SCREEN_INFO_VERSION; 283fda9279dSmrg present->info.get_crtc = nouveau_present_crtc; 284fda9279dSmrg present->info.get_ust_msc = nouveau_present_ust_msc; 285fda9279dSmrg present->info.queue_vblank = nouveau_present_vblank_queue; 286fda9279dSmrg present->info.abort_vblank = nouveau_present_vblank_abort; 287fda9279dSmrg present->info.flush = nouveau_present_flush; 288fda9279dSmrg 289fda9279dSmrg if (pNv->has_pageflip) { 290fda9279dSmrg#ifdef DRM_CAP_ASYNC_PAGE_FLIP 291fda9279dSmrg ret = drmGetCap(pNv->dev->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); 292fda9279dSmrg if (ret == 0 && value == 1) 293fda9279dSmrg present->info.capabilities |= PresentCapabilityAsync; 294fda9279dSmrg#endif 295fda9279dSmrg present->info.check_flip = nouveau_present_flip_check; 296fda9279dSmrg present->info.flip = nouveau_present_flip_next; 297fda9279dSmrg present->info.unflip = nouveau_present_flip_stop; 298fda9279dSmrg } 299fda9279dSmrg 300fda9279dSmrg return present_screen_init(screen, &present->info); 301fda9279dSmrg} 302fda9279dSmrg#endif 303