~ubuntu-branches/ubuntu/trusty/xserver-xorg-video-nouveau-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to src/nouveau_present.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2016-05-03 14:02:40 UTC
  • Revision ID: package-import@ubuntu.com-20160503140240-0owfulzviccpdncu
Tags: upstream-1.0.12
ImportĀ upstreamĀ versionĀ 1.0.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2013 Red Hat Inc.
 
3
 *
 
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:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in
 
12
 * all copies or substantial portions of the Software.
 
13
 *
 
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.
 
21
 *
 
22
 * Authors: Ben Skeggs <bskeggs@redhat.com>
 
23
 */
 
24
 
 
25
#include "nouveau_present.h"
 
26
#if defined(DRI3)
 
27
#include "nv_include.h"
 
28
#include "xf86drmMode.h"
 
29
 
 
30
struct nouveau_present {
 
31
        struct present_screen_info info;
 
32
};
 
33
 
 
34
static RRCrtcPtr
 
35
nouveau_present_crtc(WindowPtr window)
 
36
{
 
37
        ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
 
38
        xf86CrtcPtr crtc;
 
39
 
 
40
        crtc = nouveau_pick_best_crtc(scrn, FALSE,
 
41
                                  window->drawable.x,
 
42
                                  window->drawable.y,
 
43
                                  window->drawable.width,
 
44
                                  window->drawable.height);
 
45
 
 
46
        if (!crtc)
 
47
                return NULL;
 
48
 
 
49
        if (crtc->rotatedData)
 
50
                return NULL;
 
51
 
 
52
        return crtc->randr_crtc;
 
53
}
 
54
 
 
55
static int
 
56
nouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc)
 
57
{
 
58
        xf86CrtcPtr crtc = rrcrtc->devPrivate;
 
59
        NVPtr pNv = NVPTR(crtc->scrn);
 
60
        drmVBlank args;
 
61
        int ret;
 
62
 
 
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,
 
67
 
 
68
        ret = drmWaitVBlank(pNv->dev->fd, &args);
 
69
        if (ret) {
 
70
                *ust = *msc = 0;
 
71
                return BadMatch;
 
72
        }
 
73
 
 
74
        *ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec;
 
75
        *msc = args.reply.sequence;
 
76
        return Success;
 
77
}
 
78
 
 
79
struct nouveau_present_vblank {
 
80
        uint64_t msc;
 
81
};
 
82
 
 
83
static void
 
84
nouveau_present_vblank(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
 
85
{
 
86
        struct nouveau_present_vblank *event = priv;
 
87
        uint64_t msc;
 
88
 
 
89
        msc = (event->msc & 0xffffffff00000000ULL) | msc_lo;
 
90
        if (msc < event->msc)
 
91
                event->msc += 1ULL << 32;
 
92
 
 
93
        present_event_notify(name, ust, msc);
 
94
}
 
95
 
 
96
static int
 
97
nouveau_present_vblank_queue(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
 
98
{
 
99
        xf86CrtcPtr crtc = rrcrtc->devPrivate;
 
100
        NVPtr pNv = NVPTR(crtc->scrn);
 
101
        drmVBlank args;
 
102
        struct nouveau_present_vblank *event;
 
103
        void *token;
 
104
        int ret;
 
105
 
 
106
        event = drmmode_event_queue(crtc->scrn, event_id, sizeof(*event),
 
107
                                    nouveau_present_vblank, &token);
 
108
        if (!event)
 
109
                return BadAlloc;
 
110
 
 
111
        event->msc = msc;
 
112
 
 
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;
 
117
 
 
118
        while ((ret = drmWaitVBlank(pNv->dev->fd, &args)) != 0) {
 
119
                if (errno != EBUSY || drmmode_event_flush(crtc->scrn) < 0)
 
120
                        return BadAlloc;
 
121
        }
 
122
 
 
123
        return Success;
 
124
}
 
125
 
 
126
static void
 
127
nouveau_present_vblank_abort(RRCrtcPtr rrcrtc, uint64_t event_id, uint64_t msc)
 
128
{
 
129
        xf86CrtcPtr crtc = rrcrtc->devPrivate;
 
130
        drmmode_event_abort(crtc->scrn, event_id, true);
 
131
}
 
132
 
 
133
static void
 
134
nouveau_present_flush(WindowPtr window)
 
135
{
 
136
        ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
 
137
        NVPtr pNv = NVPTR(scrn);
 
138
        if (pNv->Flush)
 
139
                pNv->Flush(scrn);
 
140
}
 
141
 
 
142
struct nouveau_present_flip {
 
143
        uint64_t msc;
 
144
        uint32_t old;
 
145
        int fd;
 
146
};
 
147
 
 
148
static Bool
 
149
nouveau_present_flip_check(RRCrtcPtr rrcrtc, WindowPtr window,
 
150
                           PixmapPtr pixmap, Bool sync_flip)
 
151
{
 
152
        ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
 
153
        xf86CrtcPtr crtc = rrcrtc->devPrivate;
 
154
 
 
155
        if (!scrn->vtSema || !crtc->enabled)
 
156
                return FALSE;
 
157
 
 
158
        return TRUE;
 
159
}
 
160
 
 
161
static void
 
162
nouveau_present_flip(void *priv, uint64_t name, uint64_t ust, uint32_t msc_lo)
 
163
{
 
164
        struct nouveau_present_flip *flip = priv;
 
165
        uint64_t msc;
 
166
 
 
167
        msc = (flip->msc & ~0xffffffffULL) | msc_lo;
 
168
        if (msc < flip->msc)
 
169
                msc += 1ULL << 32;
 
170
 
 
171
        present_event_notify(name, ust, msc);
 
172
        drmModeRmFB(flip->fd, flip->old);
 
173
}
 
174
 
 
175
static Bool
 
176
nouveau_present_flip_exec(ScrnInfoPtr scrn, uint64_t event_id, int sync,
 
177
                          uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
 
178
{
 
179
        struct nouveau_pixmap *priv = nouveau_pixmap(pixmap);
 
180
        NVPtr pNv = NVPTR(scrn);
 
181
        uint32_t next_fb;
 
182
        void *token;
 
183
        int ret;
 
184
 
 
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);
 
189
        if (ret == 0) {
 
190
                struct nouveau_present_flip *flip =
 
191
                        drmmode_event_queue(scrn, event_id, sizeof(*flip),
 
192
                                            nouveau_present_flip, &token);
 
193
                if (flip) {
 
194
                        xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 
195
                        int last = 0, i;
 
196
 
 
197
                        drmmode_swap(scrn, next_fb, &flip->old);
 
198
                        flip->fd = pNv->dev->fd;
 
199
                        flip->msc = target_msc;
 
200
 
 
201
                        for (i = 0; i < config->num_crtc; i++) {
 
202
                                if (config->crtc[i]->enabled)
 
203
                                        last = i;
 
204
                        }
 
205
 
 
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]);
 
209
                                void *user = NULL;
 
210
 
 
211
                                if (!config->crtc[i]->enabled)
 
212
                                        continue;
 
213
 
 
214
                                if (token && ((crtc == sync) || (i == last))) {
 
215
                                        type |= DRM_MODE_PAGE_FLIP_EVENT;
 
216
                                        user  = token;
 
217
                                }
 
218
 
 
219
                                ret = drmModePageFlip(pNv->dev->fd, crtc,
 
220
                                                      next_fb, type, user);
 
221
                                if (ret == 0 && user) {
 
222
                                        token = NULL;
 
223
                                }
 
224
                        }
 
225
 
 
226
                        if (token == NULL) {
 
227
                                return TRUE;
 
228
                        }
 
229
 
 
230
                        drmmode_swap(scrn, flip->old, &next_fb);
 
231
                        drmmode_event_abort(scrn, event_id, false);
 
232
                }
 
233
 
 
234
                drmModeRmFB(pNv->dev->fd, next_fb);
 
235
        }
 
236
 
 
237
        return FALSE;
 
238
}
 
239
 
 
240
static Bool
 
241
nouveau_present_flip_next(RRCrtcPtr rrcrtc, uint64_t event_id,
 
242
                          uint64_t target_msc, PixmapPtr pixmap, Bool vsync)
 
243
{
 
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);
 
248
}
 
249
 
 
250
static void
 
251
nouveau_present_flip_stop(ScreenPtr screen, uint64_t event_id)
 
252
{
 
253
        PixmapPtr pixmap = screen->GetScreenPixmap(screen);
 
254
        ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 
255
        nouveau_present_flip_exec(scrn, event_id, 0, 0, pixmap, TRUE);
 
256
}
 
257
 
 
258
void
 
259
nouveau_present_fini(ScreenPtr screen)
 
260
{
 
261
        ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 
262
        NVPtr pNv = NVPTR(scrn);
 
263
        if (pNv->present) {
 
264
                free(pNv->present);
 
265
                pNv->present = NULL;
 
266
        }
 
267
}
 
268
 
 
269
Bool
 
270
nouveau_present_init(ScreenPtr screen)
 
271
{
 
272
        ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 
273
        NVPtr pNv = NVPTR(scrn);
 
274
        struct nouveau_present *present;
 
275
        uint64_t value;
 
276
        int ret;
 
277
 
 
278
        present = pNv->present = calloc(1, sizeof(*present));
 
279
        if (!present)
 
280
                return FALSE;
 
281
 
 
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;
 
288
 
 
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;
 
294
#endif
 
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;
 
298
        }
 
299
 
 
300
        return present_screen_init(screen, &present->info);
 
301
}
 
302
#endif