blob: 32572eea928c406012d39d0157f65f3b82a33c9b [file] [log] [blame]
Rob Clark4b8f30a2011-08-28 12:51:26 -05001/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3/*
4 * Copyright © 2011 Texas Instruments, Inc
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 * Rob Clark <rob@ti.com>
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
Paul Gearyf8b99692013-04-15 10:55:17 +010033#include "armsoc_driver.h"
34#include "armsoc_exa.h"
Rob Clark4b8f30a2011-08-28 12:51:26 -050035
Rob Clark4b8f30a2011-08-28 12:51:26 -050036#include "dri2.h"
37
38/* any point to support earlier? */
39#if DRI2INFOREC_VERSION < 4
40# error "Requires newer DRI2"
41#endif
42
Ray Smith3c33c3d2013-03-26 16:06:37 +000043#include "drmmode_driver.h"
44
Dave Barnish2e998952013-06-11 16:31:10 +010045struct ARMSOCDRI2BufferRec {
Rob Clark4b8f30a2011-08-28 12:51:26 -050046 DRI2BufferRec base;
47
Rob Clark99ab80d2012-04-12 17:38:07 -050048 /**
David Garbett4d37be32013-04-04 09:04:29 +010049 * Pixmap(s) that are backing the buffer
Rob Clark99ab80d2012-04-12 17:38:07 -050050 *
51 * NOTE: don't track the pixmap ptr for the front buffer if it is
52 * a window.. this could get reallocated from beneath us, so we should
53 * always use draw2pix to be sure to have the correct one
54 */
David Garbett4d37be32013-04-04 09:04:29 +010055 PixmapPtr *pPixmaps;
56
57 /**
58 * Pixmap that corresponds to the DRI2BufferRec.name, so wraps
59 * the buffer that will be used for DRI2GetBuffers calls and the
60 * next DRI2SwapBuffers call.
61 *
62 * When using more than double buffering this (and the name) are updated
63 * after a swap, before the next DRI2GetBuffers call.
64 */
65 unsigned currentPixmap;
66
67 /**
68 * Number of Pixmaps to use.
69 *
70 * This allows the number of back buffers used to be reduced, for
71 * example when allocation fails. It cannot be changed to increase the
72 * number of buffers as we would overflow the pPixmaps array.
73 */
74 unsigned numPixmaps;
Rob Clark4b8f30a2011-08-28 12:51:26 -050075
76 /**
Rob Clark0bdd3702012-04-20 14:47:51 -050077 * The DRI2 buffers are reference counted to avoid crashyness when the
78 * client detaches a dri2 drawable while we are still waiting for a
79 * page_flip event.
80 */
81 int refcnt;
82
Raymond Smith4a0c0aa2012-06-20 10:50:39 +010083 /**
David Garbett4d37be32013-04-04 09:04:29 +010084 * The value of canflip() for the previous frame. Used so that we can
85 * tell whether the buffer should be re-allocated, e.g into scanout-able
Raymond Smith4a0c0aa2012-06-20 10:50:39 +010086 * memory if the buffer can now be flipped.
87 *
88 * We don't want to re-allocate every frame because it is unnecessary
89 * overhead most of the time apart from when we switch from flipping
90 * to blitting or vice versa.
91 *
92 * We should bump the serial number of the drawable if canflip() returns
93 * something different to what is stored here, so that the DRI2 buffers
94 * will get re-allocated.
95 */
96 int previous_canflip;
97
Dave Barnish2e998952013-06-11 16:31:10 +010098};
Rob Clark4b8f30a2011-08-28 12:51:26 -050099
Dave Barnish2e998952013-06-11 16:31:10 +0100100#define ARMSOCBUF(p) ((struct ARMSOCDRI2BufferRec *)(p))
Rob Clark4b8f30a2011-08-28 12:51:26 -0500101#define DRIBUF(p) ((DRI2BufferPtr)(&(p)->base))
102
103
Rob Clark4b8f30a2011-08-28 12:51:26 -0500104static inline DrawablePtr
105dri2draw(DrawablePtr pDraw, DRI2BufferPtr buf)
106{
Dave Barnish2e998952013-06-11 16:31:10 +0100107 if (buf->attachment == DRI2BufferFrontLeft)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500108 return pDraw;
David Garbett4d37be32013-04-04 09:04:29 +0100109 else {
110 const unsigned curPix = ARMSOCBUF(buf)->currentPixmap;
111 return &(ARMSOCBUF(buf)->pPixmaps[curPix]->drawable);
112 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500113}
114
Rob Clark4b8f30a2011-08-28 12:51:26 -0500115static Bool
116canflip(DrawablePtr pDraw)
117{
Dave Barnishc50baf52012-11-29 14:39:36 +0000118 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800119 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100120 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Dave Barnishc50baf52012-11-29 14:39:36 +0000121
Dave Barnish2e998952013-06-11 16:31:10 +0100122 if (pARMSOC->NoFlip) {
Dave Barnishc50baf52012-11-29 14:39:36 +0000123 /* flipping is disabled by user option */
124 return FALSE;
Dave Barnish2e998952013-06-11 16:31:10 +0100125 } else {
Dave Barnishc50baf52012-11-29 14:39:36 +0000126 return (pDraw->type == DRAWABLE_WINDOW) &&
127 DRI2CanFlip(pDraw);
128 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500129}
130
131static inline Bool
132exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b)
133{
David Garbettae5a6362012-07-02 10:15:47 +0100134 PixmapPtr aPix = draw2pix(dri2draw(pDraw, a));
135 PixmapPtr bPix = draw2pix(dri2draw(pDraw, b));
136
Dave Barnish2e998952013-06-11 16:31:10 +0100137 ARMSOCPixmapExchange(aPix, bPix);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500138 exchange(a->name, b->name);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500139 return TRUE;
140}
141
142static PixmapPtr
143createpix(DrawablePtr pDraw)
144{
145 ScreenPtr pScreen = pDraw->pScreen;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100146 int flags = canflip(pDraw) ? ARMSOC_CREATE_PIXMAP_SCANOUT : 0;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500147 return pScreen->CreatePixmap(pScreen,
148 pDraw->width, pDraw->height, pDraw->depth, flags);
149}
150
151/**
152 * Create Buffer.
153 *
154 * Note that 'format' is used from the client side to specify the DRI buffer
155 * format, which could differ from the drawable format. For example, the
156 * drawable could be 32b RGB, but the DRI buffer some YUV format (video) or
157 * perhaps lower bit depth RGB (GL). The color conversion is handled when
158 * blitting to front buffer, and page-flipping (overlay or flipchain) can
159 * only be used if the display supports.
160 */
161static DRI2BufferPtr
Paul Geary8ffd91c2013-04-11 16:03:15 +0100162ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500163 unsigned int format)
164{
165 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800166 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100167 struct ARMSOCDRI2BufferRec *buf = calloc(1, sizeof(*buf));
David Garbett4d37be32013-04-04 09:04:29 +0100168 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Ray Smith9a3797b2013-03-15 15:33:04 +0000169 PixmapPtr pPixmap = NULL;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100170 struct armsoc_bo *bo;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500171 int ret;
172
173 DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x",
174 pDraw, attachment, format);
175
176 if (!buf) {
Ray Smith9a3797b2013-03-15 15:33:04 +0000177 ERROR_MSG("Couldn't allocate internal buffer structure");
Rob Clark4b8f30a2011-08-28 12:51:26 -0500178 return NULL;
179 }
180
181 if (attachment == DRI2BufferFrontLeft) {
182 pPixmap = draw2pix(pDraw);
Rob Clark0bdd3702012-04-20 14:47:51 -0500183 pPixmap->refcnt++;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500184 } else {
185 pPixmap = createpix(pDraw);
186 }
187
Dave Barnish2e998952013-06-11 16:31:10 +0100188 if (!pPixmap) {
Ray Smith2bc3bf62013-03-15 12:05:08 +0000189 assert(attachment != DRI2BufferFrontLeft);
190 ERROR_MSG("Failed to create back buffer for window");
Ray Smith9a3797b2013-03-15 15:33:04 +0000191 goto fail;
Ray Smith2bc3bf62013-03-15 12:05:08 +0000192 }
193
David Garbett4d37be32013-04-04 09:04:29 +0100194 if (attachment == DRI2BufferBackLeft && pARMSOC->driNumBufs > 2) {
195 buf->pPixmaps = calloc(pARMSOC->driNumBufs-1,
196 sizeof(PixmapPtr));
197 buf->numPixmaps = pARMSOC->driNumBufs-1;
198 } else {
199 buf->pPixmaps = malloc(sizeof(PixmapPtr));
200 buf->numPixmaps = 1;
201 }
202
203 if (!buf->pPixmaps) {
204 ERROR_MSG("Failed to allocate PixmapPtr array for DRI2Buffer");
205 goto fail;
206 }
207
208 buf->pPixmaps[0] = pPixmap;
209 assert(buf->currentPixmap == 0);
210
Paul Geary8ffd91c2013-04-11 16:03:15 +0100211 bo = ARMSOCPixmapBo(pPixmap);
Dave Barnish2e998952013-06-11 16:31:10 +0100212 if (!bo) {
213 ERROR_MSG(
214 "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
Ray Smith9a3797b2013-03-15 15:33:04 +0000215 goto fail;
Raymond Smithd15a7342012-05-01 12:01:52 +0100216 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500217
218 DRIBUF(buf)->attachment = attachment;
219 DRIBUF(buf)->pitch = exaGetPixmapPitch(pPixmap);
220 DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8;
221 DRIBUF(buf)->format = format;
Raymond Smith2f93cb12012-05-10 07:41:34 +0100222 DRIBUF(buf)->flags = 0;
Rob Clark0bdd3702012-04-20 14:47:51 -0500223 buf->refcnt = 1;
Liyou Zhoudcf32bd2013-09-20 16:21:11 +0100224 buf->previous_canflip = canflip(pDraw);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500225
Paul Geary8ffd91c2013-04-11 16:03:15 +0100226 ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500227 if (ret) {
228 ERROR_MSG("could not get buffer name: %d", ret);
Ray Smith9a3797b2013-03-15 15:33:04 +0000229 goto fail;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500230 }
231
David Garbett7d6a6e72012-05-11 11:52:45 +0100232 if (canflip(pDraw) && attachment != DRI2BufferFrontLeft) {
Ray Smithb4299f82013-03-13 10:08:36 +0000233 /* Create an fb around this buffer. This will fail and we will
234 * fall back to blitting if the display controller hardware
235 * cannot scan out this buffer (for example, if it doesn't
236 * support the format or there was insufficient scanout memory
237 * at buffer creation time). */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100238 int ret = armsoc_bo_add_fb(bo);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500239 if (ret) {
Ray Smithb4299f82013-03-13 10:08:36 +0000240 WARNING_MSG(
241 "Falling back to blitting a flippable window");
Rob Clark4b8f30a2011-08-28 12:51:26 -0500242 }
243 }
244
David Garbettae5a6362012-07-02 10:15:47 +0100245 /* Register Pixmap as having a buffer that can be accessed externally,
246 * so needs synchronised access */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100247 ARMSOCRegisterExternalAccess(pPixmap);
David Garbettae5a6362012-07-02 10:15:47 +0100248
Rob Clark4b8f30a2011-08-28 12:51:26 -0500249 return DRIBUF(buf);
Ray Smith9a3797b2013-03-15 15:33:04 +0000250
251fail:
Dave Barnish2e998952013-06-11 16:31:10 +0100252 if (pPixmap != NULL) {
Ray Smith9a3797b2013-03-15 15:33:04 +0000253 if (attachment != DRI2BufferFrontLeft)
Ray Smith9a3797b2013-03-15 15:33:04 +0000254 pScreen->DestroyPixmap(pPixmap);
Ray Smith9a3797b2013-03-15 15:33:04 +0000255 else
Ray Smith9a3797b2013-03-15 15:33:04 +0000256 pPixmap->refcnt--;
Ray Smith9a3797b2013-03-15 15:33:04 +0000257 }
David Garbett4d37be32013-04-04 09:04:29 +0100258 free(buf->pPixmaps);
Ray Smith9a3797b2013-03-15 15:33:04 +0000259 free(buf);
260
261 return NULL;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500262}
263
264/**
265 * Destroy Buffer
Rob Clark4b8f30a2011-08-28 12:51:26 -0500266 */
267static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100268ARMSOCDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500269{
Dave Barnish2e998952013-06-11 16:31:10 +0100270 struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer);
Rob Clark0bdd3702012-04-20 14:47:51 -0500271 /* Note: pDraw may already be deleted, so use the pPixmap here
272 * instead (since it is at least refcntd)
273 */
David Garbett4d37be32013-04-04 09:04:29 +0100274 ScreenPtr pScreen = buf->pPixmaps[0]->drawable.pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800275 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
David Garbett4d37be32013-04-04 09:04:29 +0100276 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
277 int numBuffers, i;
Rob Clark0bdd3702012-04-20 14:47:51 -0500278
279 if (--buf->refcnt > 0)
280 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500281
282 DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer);
283
David Garbett4d37be32013-04-04 09:04:29 +0100284 if (buffer->attachment == DRI2BufferBackLeft) {
285 assert(pARMSOC->driNumBufs > 1);
286 numBuffers = pARMSOC->driNumBufs-1;
287 } else
288 numBuffers = 1;
David Garbettae5a6362012-07-02 10:15:47 +0100289
David Garbett4d37be32013-04-04 09:04:29 +0100290 for (i = 0; i < numBuffers && buf->pPixmaps[i] != NULL; i++) {
291 ARMSOCDeregisterExternalAccess(buf->pPixmaps[i]);
292 pScreen->DestroyPixmap(buf->pPixmaps[i]);
293 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500294
David Garbett4d37be32013-04-04 09:04:29 +0100295 free(buf->pPixmaps);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500296 free(buf);
297}
298
Rob Clark0bdd3702012-04-20 14:47:51 -0500299static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100300ARMSOCDRI2ReferenceBuffer(DRI2BufferPtr buffer)
Rob Clark0bdd3702012-04-20 14:47:51 -0500301{
Dave Barnish2e998952013-06-11 16:31:10 +0100302 struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer);
Rob Clark0bdd3702012-04-20 14:47:51 -0500303 buf->refcnt++;
304}
305
Rob Clark4b8f30a2011-08-28 12:51:26 -0500306/**
307 *
308 */
309static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100310ARMSOCDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500311 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
312{
313 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800314 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500315 DrawablePtr pSrcDraw = dri2draw(pDraw, pSrcBuffer);
316 DrawablePtr pDstDraw = dri2draw(pDraw, pDstBuffer);
317 RegionPtr pCopyClip;
318 GCPtr pGC;
319
320 DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)",
321 pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw);
322
323 pGC = GetScratchGC(pDstDraw->depth, pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100324 if (!pGC)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500325 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500326
327 pCopyClip = REGION_CREATE(pScreen, NULL, 0);
328 RegionCopy(pCopyClip, pRegion);
329 (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0);
330 ValidateGC(pDstDraw, pGC);
331
332 /* If the dst is the framebuffer, and we had a way to
333 * schedule a deferred blit synchronized w/ vsync, that
334 * would be a nice thing to do utilize here to avoid
335 * tearing.. when we have sync object support for GEM
336 * buffers, I think we could do something more clever
337 * here.
338 */
339
340 pGC->ops->CopyArea(pSrcDraw, pDstDraw, pGC,
341 0, 0, pDraw->width, pDraw->height, 0, 0);
342
Rob Clarke450d412012-01-08 19:33:48 -0600343 FreeScratchGC(pGC);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500344}
345
346/**
347 * Get current frame count and frame count timestamp, based on drawable's
348 * crtc.
349 */
350static int
Paul Geary8ffd91c2013-04-11 16:03:15 +0100351ARMSOCDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500352{
353 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800354 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100355 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500356 drmVBlank vbl = { .request = {
357 .type = DRM_VBLANK_RELATIVE,
358 .sequence = 0,
359 } };
360 int ret;
361
Dave Barnishe762b122013-08-12 17:13:46 +0100362 if (!pARMSOC->drmmode_interface->vblank_query_supported)
363 return FALSE;
364
Paul Geary8ffd91c2013-04-11 16:03:15 +0100365 ret = drmWaitVBlank(pARMSOC->drmFD, &vbl);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500366 if (ret) {
Dave Barnishe762b122013-08-12 17:13:46 +0100367 ERROR_MSG("get vblank counter failed: %s", strerror(errno));
Rob Clark4b8f30a2011-08-28 12:51:26 -0500368 return FALSE;
369 }
370
Dave Barnish2e998952013-06-11 16:31:10 +0100371 if (ust)
372 *ust = ((CARD64)vbl.reply.tval_sec * 1000000)
373 + vbl.reply.tval_usec;
374
375 if (msc)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500376 *msc = vbl.reply.sequence;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500377
378 return TRUE;
379}
380
Paul Geary8ffd91c2013-04-11 16:03:15 +0100381#define ARMSOC_SWAP_FAKE_FLIP (1 << 0)
382#define ARMSOC_SWAP_FAIL (1 << 1)
John Sheu022833e2012-08-15 11:40:11 -0700383
Dave Barnish2e998952013-06-11 16:31:10 +0100384struct ARMSOCDRISwapCmd {
Rob Clarka6762ef2012-04-12 17:38:39 -0500385 int type;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500386 ClientPtr client;
Rob Clark0bdd3702012-04-20 14:47:51 -0500387 ScreenPtr pScreen;
388 /* Note: store drawable ID, rather than drawable. It's possible that
389 * the drawable can be destroyed while we wait for page flip event:
390 */
391 XID draw_id;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500392 DRI2BufferPtr pDstBuffer;
393 DRI2BufferPtr pSrcBuffer;
394 DRI2SwapEventPtr func;
John Sheu022833e2012-08-15 11:40:11 -0700395 int swapCount;
396 int flags;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500397 void *data;
398};
399
Dave Barnish2e998952013-06-11 16:31:10 +0100400static const char * const swap_names[] = {
Rob Clark0bdd3702012-04-20 14:47:51 -0500401 [DRI2_EXCHANGE_COMPLETE] = "exchange",
402 [DRI2_BLIT_COMPLETE] = "blit",
403 [DRI2_FLIP_COMPLETE] = "flip,"
404};
405
David Garbett4d37be32013-04-04 09:04:29 +0100406static Bool allocNextBuffer(DrawablePtr pDraw, PixmapPtr *ppPixmap,
407 uint32_t *name) {
408 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800409 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
David Garbett4d37be32013-04-04 09:04:29 +0100410 struct armsoc_bo *bo;
411 PixmapPtr pPixmap;
412 int ret;
413 uint32_t new_name;
414 Bool extRegistered = FALSE;
415
416 pPixmap = createpix(pDraw);
417
418 if (!pPixmap)
419 goto error;
420
421 bo = ARMSOCPixmapBo(pPixmap);
422 if (!bo) {
423 WARNING_MSG(
424 "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
425 goto error;
426 }
427
428 ARMSOCRegisterExternalAccess(pPixmap);
429 extRegistered = TRUE;
430
431 ret = armsoc_bo_get_name(bo, &new_name);
432 if (ret) {
433 ERROR_MSG("Could not get buffer name: %d", ret);
434 goto error;
435 }
436
437 if (!armsoc_bo_get_fb(bo)) {
438 ret = armsoc_bo_add_fb(bo);
439 /* Should always be able to add fb, as we only add more buffers
440 * when flipping*/
441 if (ret) {
442 ERROR_MSG(
443 "Could not add framebuffer to additional back buffer");
444 goto error;
445 }
446 }
447
448 /* No errors, update pixmap and name */
449 *ppPixmap = pPixmap;
450 *name = new_name;
451
452 return TRUE;
453
454error:
455 /* revert to existing pixmap */
456 if (pPixmap) {
457 if (extRegistered)
458 ARMSOCDeregisterExternalAccess(pPixmap);
459 pScreen->DestroyPixmap(pPixmap);
460 }
461
462 return FALSE;
463}
464
465static void nextBuffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *backBuf)
466{
467 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800468 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
David Garbett4d37be32013-04-04 09:04:29 +0100469 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
470
471 if (pARMSOC->driNumBufs <= 2) {
472 /*Only using double buffering, leave the pixmap as-is */
473 return;
474 }
475
476 backBuf->currentPixmap++;
477 backBuf->currentPixmap %= backBuf->numPixmaps;
478
479 if (backBuf->pPixmaps[backBuf->currentPixmap]) {
480 /* Already allocated the next buffer - get the name and
481 * early-out */
482 struct armsoc_bo *bo;
483 int ret;
484
485 bo = ARMSOCPixmapBo(backBuf->pPixmaps[backBuf->currentPixmap]);
486 assert(bo);
487 ret = armsoc_bo_get_name(bo, &DRIBUF(backBuf)->name);
488 assert(!ret);
489 } else {
490 Bool ret;
491 PixmapPtr * const curBackPix =
492 &backBuf->pPixmaps[backBuf->currentPixmap];
493 ret = allocNextBuffer(pDraw, curBackPix,
494 &DRIBUF(backBuf)->name);
495 if (!ret) {
496 /* can't have failed on the first buffer */
497 assert(backBuf->currentPixmap > 0);
498 /* Fall back to last buffer */
499 backBuf->currentPixmap--;
500 WARNING_MSG(
501 "Failed to use the requested %d-buffering due to an allocation failure.\n"
502 "Falling back to %d-buffering for this DRI2Drawable",
503 backBuf->numPixmaps+1,
504 backBuf->currentPixmap+2);
505 backBuf->numPixmaps = backBuf->currentPixmap+1;
506 }
507 }
508}
509
510static struct armsoc_bo *boFromBuffer(DRI2BufferPtr buf)
511{
512 PixmapPtr pPixmap;
513 struct ARMSOCPixmapPrivRec *priv;
514
515 pPixmap = ARMSOCBUF(buf)->pPixmaps[ARMSOCBUF(buf)->currentPixmap];
516 priv = exaGetPixmapDriverPrivate(pPixmap);
517 return priv->bo;
518}
519
Rob Clark4b8f30a2011-08-28 12:51:26 -0500520void
Dave Barnish2e998952013-06-11 16:31:10 +0100521ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500522{
Rob Clark0bdd3702012-04-20 14:47:51 -0500523 ScreenPtr pScreen = cmd->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800524 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100525 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark0bdd3702012-04-20 14:47:51 -0500526 DrawablePtr pDraw = NULL;
527 int status;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100528 struct armsoc_bo *old_src_bo, *old_dst_bo;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500529
John Sheu022833e2012-08-15 11:40:11 -0700530 if (--cmd->swapCount > 0)
531 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500532
Sean Paul269c9712012-09-04 15:17:33 -0700533 /* Save the old source bo for unreference below */
David Garbett4d37be32013-04-04 09:04:29 +0100534 old_src_bo = boFromBuffer(cmd->pSrcBuffer);
535 old_dst_bo = boFromBuffer(cmd->pDstBuffer);
Sean Paul269c9712012-09-04 15:17:33 -0700536
Paul Geary8ffd91c2013-04-11 16:03:15 +0100537 if ((cmd->flags & ARMSOC_SWAP_FAIL) == 0) {
John Sheu022833e2012-08-15 11:40:11 -0700538 DEBUG_MSG("%s complete: %d -> %d", swap_names[cmd->type],
Dave Barnish2e998952013-06-11 16:31:10 +0100539 cmd->pSrcBuffer->attachment,
540 cmd->pDstBuffer->attachment);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500541
John Sheu022833e2012-08-15 11:40:11 -0700542 status = dixLookupDrawable(&pDraw, cmd->draw_id, serverClient,
543 M_ANY, DixWriteAccess);
544
545 if (status == Success) {
Dave Barnish2e998952013-06-11 16:31:10 +0100546 if (cmd->type != DRI2_BLIT_COMPLETE &&
547 (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) {
John Sheu022833e2012-08-15 11:40:11 -0700548 assert(cmd->type == DRI2_FLIP_COMPLETE);
Dave Barnish2e998952013-06-11 16:31:10 +0100549 exchangebufs(pDraw, cmd->pSrcBuffer,
550 cmd->pDstBuffer);
David Garbett4d37be32013-04-04 09:04:29 +0100551
552 if (cmd->pSrcBuffer->attachment ==
553 DRI2BufferBackLeft)
554 nextBuffer(pDraw,
555 ARMSOCBUF(cmd->pSrcBuffer));
John Sheu022833e2012-08-15 11:40:11 -0700556 }
557
558 DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type,
559 cmd->func, cmd->data);
560
Dave Barnish2e998952013-06-11 16:31:10 +0100561 if (cmd->type != DRI2_BLIT_COMPLETE &&
562 (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) {
John Sheu022833e2012-08-15 11:40:11 -0700563 assert(cmd->type == DRI2_FLIP_COMPLETE);
David Garbett4d37be32013-04-04 09:04:29 +0100564 set_scanout_bo(pScrn,
565 boFromBuffer(cmd->pDstBuffer));
John Sheu022833e2012-08-15 11:40:11 -0700566 }
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100567 }
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100568 }
David Garbett3688b332012-05-11 12:17:34 +0100569
Rob Clark0bdd3702012-04-20 14:47:51 -0500570 /* drop extra refcnt we obtained prior to swap:
571 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100572 ARMSOCDRI2DestroyBuffer(pDraw, cmd->pSrcBuffer);
573 ARMSOCDRI2DestroyBuffer(pDraw, cmd->pDstBuffer);
574 armsoc_bo_unreference(old_src_bo);
575 armsoc_bo_unreference(old_dst_bo);
576 pARMSOC->pending_flips--;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500577
578 free(cmd);
579}
580
581/**
582 * ScheduleSwap is responsible for requesting a DRM vblank event for the
583 * appropriate frame.
584 *
585 * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
586 * the vblank requested can simply be the last queued swap frame + the swap
587 * interval for the drawable.
588 *
589 * In the case of a page flip, we request an event for the last queued swap
590 * frame + swap interval - 1, since we'll need to queue the flip for the frame
591 * immediately following the received event.
592 */
593static int
Paul Geary8ffd91c2013-04-11 16:03:15 +0100594ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500595 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer,
596 CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
597 DRI2SwapEventPtr func, void *data)
598{
599 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800600 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100601 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
602 struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer);
603 struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer);
604 struct ARMSOCDRISwapCmd *cmd = calloc(1, sizeof(*cmd));
David Garbett4d37be32013-04-04 09:04:29 +0100605 struct armsoc_bo *src_bo, *dst_bo;
David Garbett7d6a6e72012-05-11 11:52:45 +0100606 int src_fb_id, dst_fb_id;
Ray Smithedccfd82013-05-31 15:57:12 +0100607 int new_canflip, ret, do_flip;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500608
Dave Barnish2e998952013-06-11 16:31:10 +0100609 if (!cmd)
Paul Geary6fe52f32013-04-03 11:12:24 +0100610 return FALSE;
Paul Geary6fe52f32013-04-03 11:12:24 +0100611
Rob Clark4b8f30a2011-08-28 12:51:26 -0500612 cmd->client = client;
Rob Clark0bdd3702012-04-20 14:47:51 -0500613 cmd->pScreen = pScreen;
614 cmd->draw_id = pDraw->id;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500615 cmd->pSrcBuffer = pSrcBuffer;
616 cmd->pDstBuffer = pDstBuffer;
John Sheu022833e2012-08-15 11:40:11 -0700617 cmd->swapCount = 0;
618 cmd->flags = 0;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500619 cmd->func = func;
620 cmd->data = data;
621
622 DEBUG_MSG("%d -> %d", pSrcBuffer->attachment, pDstBuffer->attachment);
623
Rob Clark0bdd3702012-04-20 14:47:51 -0500624 /* obtain extra ref on buffers to avoid them going away while we await
625 * the page flip event:
626 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100627 ARMSOCDRI2ReferenceBuffer(pSrcBuffer);
628 ARMSOCDRI2ReferenceBuffer(pDstBuffer);
629 pARMSOC->pending_flips++;
Rob Clark0bdd3702012-04-20 14:47:51 -0500630
David Garbett4d37be32013-04-04 09:04:29 +0100631 src_bo = boFromBuffer(pSrcBuffer);
632 dst_bo = boFromBuffer(pDstBuffer);
David Garbett7d6a6e72012-05-11 11:52:45 +0100633
David Garbett4d37be32013-04-04 09:04:29 +0100634 src_fb_id = armsoc_bo_get_fb(src_bo);
635 dst_fb_id = armsoc_bo_get_fb(dst_bo);
David Garbett7d6a6e72012-05-11 11:52:45 +0100636
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100637 new_canflip = canflip(pDraw);
Liyou Zhoudcf32bd2013-09-20 16:21:11 +0100638 if ((src->previous_canflip != new_canflip) ||
639 (dst->previous_canflip != new_canflip)) {
Dave Barnish2e998952013-06-11 16:31:10 +0100640 /* The drawable has transitioned between being flippable and
641 * non-flippable or vice versa. Bump the serial number to force
642 * the DRI2 buffers to be re-allocated during the next frame so
643 * that:
644 * - It is able to be scanned out
645 * (if drawable is now flippable), or
646 * - It is not taking up possibly scarce scanout-able memory
647 * (if drawable is now not flippable)
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100648 */
649
650 PixmapPtr pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
651 pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER;
652 }
653
654 src->previous_canflip = new_canflip;
655 dst->previous_canflip = new_canflip;
656
David Garbett4d37be32013-04-04 09:04:29 +0100657 armsoc_bo_reference(src_bo);
658 armsoc_bo_reference(dst_bo);
Ray Smithedccfd82013-05-31 15:57:12 +0100659
660 do_flip = src_fb_id && dst_fb_id && canflip(pDraw);
661
Dave Barnishe762b122013-08-12 17:13:46 +0100662 /* After a resolution change the back buffer (src) will still be
663 * of the original size. We can't sensibly flip to a framebuffer of
664 * a different size to the current resolution (it will look corrupted)
665 * so we must do a copy for this frame (which will clip the contents
666 * as expected).
Ray Smithedccfd82013-05-31 15:57:12 +0100667 *
Dave Barnishe762b122013-08-12 17:13:46 +0100668 * Once the client calls DRI2GetBuffers again, it will receive a new
669 * back buffer of the same size as the new resolution, and subsequent
670 * DRI2SwapBuffers will result in a flip.
Ray Smithedccfd82013-05-31 15:57:12 +0100671 */
Dave Barnishe762b122013-08-12 17:13:46 +0100672 do_flip = do_flip &&
673 (armsoc_bo_width(src_bo) == armsoc_bo_width(dst_bo));
674 do_flip = do_flip &&
675 (armsoc_bo_height(src_bo) == armsoc_bo_height(dst_bo));
Ray Smithedccfd82013-05-31 15:57:12 +0100676
677 if (do_flip) {
David Garbett7d6a6e72012-05-11 11:52:45 +0100678 DEBUG_MSG("can flip: %d -> %d", src_fb_id, dst_fb_id);
Rob Clarka6762ef2012-04-12 17:38:39 -0500679 cmd->type = DRI2_FLIP_COMPLETE;
Dave Barnish2e998952013-06-11 16:31:10 +0100680 /* TODO: MIDEGL-1461: Handle rollback if multiple CRTC flip is
681 * only partially successful
John Sheu022833e2012-08-15 11:40:11 -0700682 */
683 ret = drmmode_page_flip(pDraw, src_fb_id, cmd);
684
Dave Barnish2e998952013-06-11 16:31:10 +0100685 /* If using page flip events, we'll trigger an immediate
686 * completion in the case that no CRTCs were enabled to be
687 * flipped. If not using page flip events, trigger immediate
688 * completion unconditionally.
John Sheu022833e2012-08-15 11:40:11 -0700689 */
690 if (ret < 0) {
691 /*
692 * Error while flipping; bail.
693 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100694 cmd->flags |= ARMSOC_SWAP_FAIL;
Ray Smith3c33c3d2013-03-26 16:06:37 +0000695
Dave Barnishde45ed42013-06-05 13:47:56 +0100696 if (pARMSOC->drmmode_interface->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +0000697 cmd->swapCount = -(ret + 1);
698 else
699 cmd->swapCount = 0;
700
John Sheu022833e2012-08-15 11:40:11 -0700701 if (cmd->swapCount == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100702 ARMSOCDRI2SwapComplete(cmd);
Dave Barnish2e998952013-06-11 16:31:10 +0100703
John Sheu022833e2012-08-15 11:40:11 -0700704 return FALSE;
705 } else {
706 if (ret == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100707 cmd->flags |= ARMSOC_SWAP_FAKE_FLIP;
Ray Smith3c33c3d2013-03-26 16:06:37 +0000708
Dave Barnishde45ed42013-06-05 13:47:56 +0100709 if (pARMSOC->drmmode_interface->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +0000710 cmd->swapCount = ret;
711 else
712 cmd->swapCount = 0;
713
John Sheu022833e2012-08-15 11:40:11 -0700714 if (cmd->swapCount == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100715 ARMSOCDRI2SwapComplete(cmd);
John Sheu022833e2012-08-15 11:40:11 -0700716 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500717 } else {
718 /* fallback to blit: */
719 BoxRec box = {
720 .x1 = 0,
721 .y1 = 0,
722 .x2 = pDraw->width,
723 .y2 = pDraw->height,
724 };
725 RegionRec region;
726 RegionInit(&region, &box, 0);
Paul Geary8ffd91c2013-04-11 16:03:15 +0100727 ARMSOCDRI2CopyRegion(pDraw, &region, pDstBuffer, pSrcBuffer);
Rob Clarka6762ef2012-04-12 17:38:39 -0500728 cmd->type = DRI2_BLIT_COMPLETE;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100729 ARMSOCDRI2SwapComplete(cmd);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500730 }
731
732 return TRUE;
733}
734
735/**
736 * Request a DRM event when the requested conditions will be satisfied.
737 *
738 * We need to handle the event and ask the server to wake up the client when
739 * we receive it.
740 */
741static int
Dave Barnish2e998952013-06-11 16:31:10 +0100742ARMSOCDRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr pDraw,
743 CARD64 target_msc, CARD64 divisor, CARD64 remainder)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500744{
745 ScreenPtr pScreen = pDraw->pScreen;
Daniel Kurtz0361e002013-08-14 21:07:01 +0800746 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500747
Rob Clark4b8f30a2011-08-28 12:51:26 -0500748 ERROR_MSG("not implemented");
749 return FALSE;
750}
751
752/**
753 * The DRI2 ScreenInit() function.. register our handler fxns w/ DRI2 core
754 */
755Bool
Paul Geary8ffd91c2013-04-11 16:03:15 +0100756ARMSOCDRI2ScreenInit(ScreenPtr pScreen)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500757{
Daniel Kurtz0361e002013-08-14 21:07:01 +0800758 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100759 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500760 DRI2InfoRec info = {
Dave Barnish2e998952013-06-11 16:31:10 +0100761 .version = 5,
762 .fd = pARMSOC->drmFD,
763 .driverName = "armsoc",
764 .deviceName = pARMSOC->deviceName,
765 .CreateBuffer = ARMSOCDRI2CreateBuffer,
766 .DestroyBuffer = ARMSOCDRI2DestroyBuffer,
767 .CopyRegion = ARMSOCDRI2CopyRegion,
768 .ScheduleSwap = ARMSOCDRI2ScheduleSwap,
769 .ScheduleWaitMSC = ARMSOCDRI2ScheduleWaitMSC,
770 .GetMSC = ARMSOCDRI2GetMSC,
771 .AuthMagic = drmAuthMagic,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500772 };
773 int minor = 1, major = 0;
774
Dave Barnish2e998952013-06-11 16:31:10 +0100775 if (xf86LoaderCheckSymbol("DRI2Version"))
Rob Clark4b8f30a2011-08-28 12:51:26 -0500776 DRI2Version(&major, &minor);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500777
778 if (minor < 1) {
779 WARNING_MSG("DRI2 requires DRI2 module version 1.1.0 or later");
780 return FALSE;
781 }
782
783 return DRI2ScreenInit(pScreen, &info);
784}
785
786/**
787 * The DRI2 CloseScreen() function.. unregister ourself w/ DRI2 core.
788 */
789void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100790ARMSOCDRI2CloseScreen(ScreenPtr pScreen)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500791{
Daniel Kurtz0361e002013-08-14 21:07:01 +0800792 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100793 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Paul Geary8ffd91c2013-04-11 16:03:15 +0100794 while (pARMSOC->pending_flips > 0) {
Rob Clark67b875f2012-04-20 19:13:57 -0500795 DEBUG_MSG("waiting..");
796 drmmode_wait_for_event(pScrn);
797 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500798 DRI2CloseScreen(pScreen);
799}