2
* Copyright 2013 Red Hat Inc.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
* OTHER DEALINGS IN THE SOFTWARE.
22
* Authors: Ben Skeggs <bskeggs@redhat.com>
25
#include "nouveau_present.h"
27
#include "nv_include.h"
28
#include "xf86drmMode.h"
30
struct nouveau_present {
31
struct present_screen_info info;
35
nouveau_present_crtc(WindowPtr window)
37
ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
40
crtc = nouveau_pick_best_crtc(scrn, FALSE,
43
window->drawable.width,
44
window->drawable.height);
49
if (crtc->rotatedData)
52
return crtc->randr_crtc;
56
nouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc)
58
xf86CrtcPtr crtc = rrcrtc->devPrivate;
59
NVPtr pNv = NVPTR(crtc->scrn);
63
args.request.type = DRM_VBLANK_RELATIVE;
64
args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT;
65
args.request.sequence = 0,
66
args.request.signal = 0,
68
ret = drmWaitVBlank(pNv->dev->fd, &args);
74
*ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec;
75
*msc = args.reply.sequence;
79
struct nouveau_present_vblank {
84
nouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
86
struct nouveau_present_vblank *event = priv;
89
msc = (event->msc & 0xffffffff00000000ULL) | msc_lo;
91
event->msc += 1ULL << 32;
93
present_event_notify(name, ust, msc);
97
nouveau_present_vblank_queue(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
99
xf86CrtcPtr crtc = rrcrtc->devPrivate;
100
NVPtr pNv = NVPTR(crtc->scrn);
102
struct nouveau_present_vblank *event;
106
event = drmmode_event_queue(crtc->scrn, event_id, sizeof(*event),
107
nouveau_present_vblank, &token);
113
args.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
114
args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT;
115
args.request.sequence = msc;
116
args.request.signal = (unsigned long)token;
118
while ((ret = drmWaitVBlank(pNv->dev->fd, &args)) != 0) {
119
if (errno != EBUSY || drmmode_event_flush(crtc->scrn) < 0)
127
nouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
129
xf86CrtcPtr crtc = rrcrtc->devPrivate;
130
drmmode_event_abort(crtc->scrn, event_id, true);
134
nouveau_present_flush(WindowPtr window)
136
ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
137
NVPtr pNv = NVPTR(scrn);
142
struct nouveau_present_flip {
149
nouveau_present_flip_check(RRCrtcPtr rrcrtc, WindowPtr window,
150
PixmapPtr pixmap, Bool sync_flip)
152
ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
153
xf86CrtcPtr crtc = rrcrtc->devPrivate;
155
if (!scrn->vtSema || !crtc->enabled)
162
nouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
164
struct nouveau_present_flip *flip = priv;
167
msc = (flip->msc & ~0xffffffffULL) | msc_lo;
171
present_event_notify(name, ust, msc);
172
drmModeRmFB(flip->fd, flip->old);
176
nouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync,
177
uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
179
struct nouveau_pixmap *priv = nouveau_pixmap(pixmap);
180
NVPtr pNv = NVPTR(scrn);
185
ret = drmModeAddFB(pNv->dev->fd, pixmap->drawable.width,
186
pixmap->drawable.height, pixmap->drawable.depth,
187
pixmap->drawable.bitsPerPixel, pixmap->devKind,
188
priv->bo->handle, &next_fb);
190
struct nouveau_present_flip *flip =
191
drmmode_event_queue(scrn, event_id, sizeof(*flip),
192
nouveau_present_flip, &token);
194
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
197
drmmode_swap(scrn, next_fb, &flip->old);
198
flip->fd = pNv->dev->fd;
199
flip->msc = target_msc;
201
for (i = 0; i < config->num_crtc; i++) {
202
if (config->crtc[i]->enabled)
206
for (i = 0; i < config->num_crtc; i++) {
207
int type = vsync ? 0 : DRM_MODE_PAGE_FLIP_ASYNC;
208
int crtc = drmmode_crtc(config->crtc[i]);
211
if (!config->crtc[i]->enabled)
214
if (token && ((crtc == sync) || (i == last))) {
215
type |= DRM_MODE_PAGE_FLIP_EVENT;
219
ret = drmModePageFlip(pNv->dev->fd, crtc,
220
next_fb, type, user);
221
if (ret == 0 && user) {
230
drmmode_swap(scrn, flip->old, &next_fb);
231
drmmode_event_abort(scrn, event_id, false);
234
drmModeRmFB(pNv->dev->fd, next_fb);
241
nouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id,
242
uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
244
xf86CrtcPtr crtc = rrcrtc->devPrivate;
245
ScrnInfoPtr scrn = crtc->scrn;
246
return nouveau_present_flip_exec(scrn, event_id, drmmode_crtc(crtc),
247
target_msc, pixmap, vsync);
251
nouveau_present_flip_stop(ScreenPtr screen, uint64_t event_id)
253
PixmapPtr pixmap = screen->GetScreenPixmap(screen);
254
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
255
nouveau_present_flip_exec(scrn, event_id, 0, 0, pixmap, TRUE);
259
nouveau_present_fini(ScreenPtr screen)
261
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
262
NVPtr pNv = NVPTR(scrn);
270
nouveau_present_init(ScreenPtr screen)
272
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
273
NVPtr pNv = NVPTR(scrn);
274
struct nouveau_present *present;
278
present = pNv->present = calloc(1, sizeof(*present));
282
present->info.version = PRESENT_SCREEN_INFO_VERSION;
283
present->info.get_crtc = nouveau_present_crtc;
284
present->info.get_ust_msc = nouveau_present_ust_msc;
285
present->info.queue_vblank = nouveau_present_vblank_queue;
286
present->info.abort_vblank = nouveau_present_vblank_abort;
287
present->info.flush = nouveau_present_flush;
289
if (pNv->has_pageflip) {
290
#ifdef DRM_CAP_ASYNC_PAGE_FLIP
291
ret = drmGetCap(pNv->dev->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
292
if (ret == 0 && value == 1)
293
present->info.capabilities |= PresentCapabilityAsync;
295
present->info.check_flip = nouveau_present_flip_check;
296
present->info.flip = nouveau_present_flip_next;
297
present->info.unflip = nouveau_present_flip_stop;
300
return present_screen_init(screen, &present->info);