blob: e06c77f9eb48f20959310dc19faac3359867a612 [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 /**
49 * Pixmap that is backing the buffer
50 *
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 */
Rob Clark4b8f30a2011-08-28 12:51:26 -050055 PixmapPtr pPixmap;
56
57 /**
Rob Clark0bdd3702012-04-20 14:47:51 -050058 * The DRI2 buffers are reference counted to avoid crashyness when the
59 * client detaches a dri2 drawable while we are still waiting for a
60 * page_flip event.
61 */
62 int refcnt;
63
Raymond Smith4a0c0aa2012-06-20 10:50:39 +010064 /**
65 * The value of canflip() for the previous frame. Used so that we can tell
66 * whether the buffer should be re-allocated, e.g into scanout-able
67 * memory if the buffer can now be flipped.
68 *
69 * We don't want to re-allocate every frame because it is unnecessary
70 * overhead most of the time apart from when we switch from flipping
71 * to blitting or vice versa.
72 *
73 * We should bump the serial number of the drawable if canflip() returns
74 * something different to what is stored here, so that the DRI2 buffers
75 * will get re-allocated.
76 */
77 int previous_canflip;
78
Dave Barnish2e998952013-06-11 16:31:10 +010079};
Rob Clark4b8f30a2011-08-28 12:51:26 -050080
Dave Barnish2e998952013-06-11 16:31:10 +010081#define ARMSOCBUF(p) ((struct ARMSOCDRI2BufferRec *)(p))
Rob Clark4b8f30a2011-08-28 12:51:26 -050082#define DRIBUF(p) ((DRI2BufferPtr)(&(p)->base))
83
84
Rob Clark4b8f30a2011-08-28 12:51:26 -050085static inline DrawablePtr
86dri2draw(DrawablePtr pDraw, DRI2BufferPtr buf)
87{
Dave Barnish2e998952013-06-11 16:31:10 +010088 if (buf->attachment == DRI2BufferFrontLeft)
Rob Clark4b8f30a2011-08-28 12:51:26 -050089 return pDraw;
Dave Barnish2e998952013-06-11 16:31:10 +010090 else
Paul Geary8ffd91c2013-04-11 16:03:15 +010091 return &(ARMSOCBUF(buf)->pPixmap->drawable);
Rob Clark4b8f30a2011-08-28 12:51:26 -050092}
93
Rob Clark4b8f30a2011-08-28 12:51:26 -050094static Bool
95canflip(DrawablePtr pDraw)
96{
Dave Barnishc50baf52012-11-29 14:39:36 +000097 ScreenPtr pScreen = pDraw->pScreen;
98 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +010099 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Dave Barnishc50baf52012-11-29 14:39:36 +0000100
Dave Barnish2e998952013-06-11 16:31:10 +0100101 if (pARMSOC->NoFlip) {
Dave Barnishc50baf52012-11-29 14:39:36 +0000102 /* flipping is disabled by user option */
103 return FALSE;
Dave Barnish2e998952013-06-11 16:31:10 +0100104 } else {
Dave Barnishc50baf52012-11-29 14:39:36 +0000105 return (pDraw->type == DRAWABLE_WINDOW) &&
106 DRI2CanFlip(pDraw);
107 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500108}
109
110static inline Bool
111exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b)
112{
David Garbettae5a6362012-07-02 10:15:47 +0100113 PixmapPtr aPix = draw2pix(dri2draw(pDraw, a));
114 PixmapPtr bPix = draw2pix(dri2draw(pDraw, b));
115
Dave Barnish2e998952013-06-11 16:31:10 +0100116 ARMSOCPixmapExchange(aPix, bPix);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500117 exchange(a->name, b->name);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500118 return TRUE;
119}
120
121static PixmapPtr
122createpix(DrawablePtr pDraw)
123{
124 ScreenPtr pScreen = pDraw->pScreen;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100125 int flags = canflip(pDraw) ? ARMSOC_CREATE_PIXMAP_SCANOUT : 0;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500126 return pScreen->CreatePixmap(pScreen,
127 pDraw->width, pDraw->height, pDraw->depth, flags);
128}
129
130/**
131 * Create Buffer.
132 *
133 * Note that 'format' is used from the client side to specify the DRI buffer
134 * format, which could differ from the drawable format. For example, the
135 * drawable could be 32b RGB, but the DRI buffer some YUV format (video) or
136 * perhaps lower bit depth RGB (GL). The color conversion is handled when
137 * blitting to front buffer, and page-flipping (overlay or flipchain) can
138 * only be used if the display supports.
139 */
140static DRI2BufferPtr
Paul Geary8ffd91c2013-04-11 16:03:15 +0100141ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500142 unsigned int format)
143{
144 ScreenPtr pScreen = pDraw->pScreen;
145 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100146 struct ARMSOCDRI2BufferRec *buf = calloc(1, sizeof(*buf));
Ray Smith9a3797b2013-03-15 15:33:04 +0000147 PixmapPtr pPixmap = NULL;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100148 struct armsoc_bo *bo;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500149 int ret;
150
151 DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x",
152 pDraw, attachment, format);
153
154 if (!buf) {
Ray Smith9a3797b2013-03-15 15:33:04 +0000155 ERROR_MSG("Couldn't allocate internal buffer structure");
Rob Clark4b8f30a2011-08-28 12:51:26 -0500156 return NULL;
157 }
158
159 if (attachment == DRI2BufferFrontLeft) {
160 pPixmap = draw2pix(pDraw);
Rob Clark0bdd3702012-04-20 14:47:51 -0500161 pPixmap->refcnt++;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500162 } else {
163 pPixmap = createpix(pDraw);
164 }
165
Dave Barnish2e998952013-06-11 16:31:10 +0100166 if (!pPixmap) {
Ray Smith2bc3bf62013-03-15 12:05:08 +0000167 assert(attachment != DRI2BufferFrontLeft);
168 ERROR_MSG("Failed to create back buffer for window");
Ray Smith9a3797b2013-03-15 15:33:04 +0000169 goto fail;
Ray Smith2bc3bf62013-03-15 12:05:08 +0000170 }
171
Paul Geary8ffd91c2013-04-11 16:03:15 +0100172 bo = ARMSOCPixmapBo(pPixmap);
Dave Barnish2e998952013-06-11 16:31:10 +0100173 if (!bo) {
174 ERROR_MSG(
175 "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
Ray Smith9a3797b2013-03-15 15:33:04 +0000176 goto fail;
Raymond Smithd15a7342012-05-01 12:01:52 +0100177 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500178
179 DRIBUF(buf)->attachment = attachment;
180 DRIBUF(buf)->pitch = exaGetPixmapPitch(pPixmap);
181 DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8;
182 DRIBUF(buf)->format = format;
Raymond Smith2f93cb12012-05-10 07:41:34 +0100183 DRIBUF(buf)->flags = 0;
Rob Clark0bdd3702012-04-20 14:47:51 -0500184 buf->refcnt = 1;
185 buf->pPixmap = pPixmap;
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100186 buf->previous_canflip = -1;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500187
Paul Geary8ffd91c2013-04-11 16:03:15 +0100188 ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500189 if (ret) {
190 ERROR_MSG("could not get buffer name: %d", ret);
Ray Smith9a3797b2013-03-15 15:33:04 +0000191 goto fail;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500192 }
193
Dave Barnish2e998952013-06-11 16:31:10 +0100194 /* Q: how to know across ARMSOC generations what formats the display
195 * can support directly?
Rob Clark4b8f30a2011-08-28 12:51:26 -0500196 * A: attempt to create a drm_framebuffer, and if that fails then the
David Garbett7d6a6e72012-05-11 11:52:45 +0100197 * hw must not support.. then fall back to blitting
Rob Clark4b8f30a2011-08-28 12:51:26 -0500198 */
David Garbett7d6a6e72012-05-11 11:52:45 +0100199 if (canflip(pDraw) && attachment != DRI2BufferFrontLeft) {
Paul Geary8ffd91c2013-04-11 16:03:15 +0100200 int ret = armsoc_bo_add_fb(bo);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500201 if (ret) {
202 /* to-bad, so-sad, we can't flip */
203 WARNING_MSG("could not create fb: %d", ret);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500204 }
205 }
206
David Garbettae5a6362012-07-02 10:15:47 +0100207 /* Register Pixmap as having a buffer that can be accessed externally,
208 * so needs synchronised access */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100209 ARMSOCRegisterExternalAccess(pPixmap);
David Garbettae5a6362012-07-02 10:15:47 +0100210
Rob Clark4b8f30a2011-08-28 12:51:26 -0500211 return DRIBUF(buf);
Ray Smith9a3797b2013-03-15 15:33:04 +0000212
213fail:
Dave Barnish2e998952013-06-11 16:31:10 +0100214 if (pPixmap != NULL) {
Ray Smith9a3797b2013-03-15 15:33:04 +0000215 if (attachment != DRI2BufferFrontLeft)
Ray Smith9a3797b2013-03-15 15:33:04 +0000216 pScreen->DestroyPixmap(pPixmap);
Ray Smith9a3797b2013-03-15 15:33:04 +0000217 else
Ray Smith9a3797b2013-03-15 15:33:04 +0000218 pPixmap->refcnt--;
Ray Smith9a3797b2013-03-15 15:33:04 +0000219 }
220 free(buf);
221
222 return NULL;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500223}
224
225/**
226 * Destroy Buffer
Rob Clark4b8f30a2011-08-28 12:51:26 -0500227 */
228static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100229ARMSOCDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500230{
Dave Barnish2e998952013-06-11 16:31:10 +0100231 struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer);
Rob Clark0bdd3702012-04-20 14:47:51 -0500232 /* Note: pDraw may already be deleted, so use the pPixmap here
233 * instead (since it is at least refcntd)
234 */
235 ScreenPtr pScreen = buf->pPixmap->drawable.pScreen;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500236 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Rob Clark0bdd3702012-04-20 14:47:51 -0500237
238 if (--buf->refcnt > 0)
239 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500240
241 DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer);
242
Paul Geary8ffd91c2013-04-11 16:03:15 +0100243 ARMSOCDeregisterExternalAccess(buf->pPixmap);
David Garbettae5a6362012-07-02 10:15:47 +0100244
Rob Clark0bdd3702012-04-20 14:47:51 -0500245 pScreen->DestroyPixmap(buf->pPixmap);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500246
247 free(buf);
248}
249
Rob Clark0bdd3702012-04-20 14:47:51 -0500250static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100251ARMSOCDRI2ReferenceBuffer(DRI2BufferPtr buffer)
Rob Clark0bdd3702012-04-20 14:47:51 -0500252{
Dave Barnish2e998952013-06-11 16:31:10 +0100253 struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer);
Rob Clark0bdd3702012-04-20 14:47:51 -0500254 buf->refcnt++;
255}
256
Rob Clark4b8f30a2011-08-28 12:51:26 -0500257/**
258 *
259 */
260static void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100261ARMSOCDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500262 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
263{
264 ScreenPtr pScreen = pDraw->pScreen;
265 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
266 DrawablePtr pSrcDraw = dri2draw(pDraw, pSrcBuffer);
267 DrawablePtr pDstDraw = dri2draw(pDraw, pDstBuffer);
268 RegionPtr pCopyClip;
269 GCPtr pGC;
270
271 DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)",
272 pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw);
273
274 pGC = GetScratchGC(pDstDraw->depth, pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100275 if (!pGC)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500276 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500277
278 pCopyClip = REGION_CREATE(pScreen, NULL, 0);
279 RegionCopy(pCopyClip, pRegion);
280 (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0);
281 ValidateGC(pDstDraw, pGC);
282
283 /* If the dst is the framebuffer, and we had a way to
284 * schedule a deferred blit synchronized w/ vsync, that
285 * would be a nice thing to do utilize here to avoid
286 * tearing.. when we have sync object support for GEM
287 * buffers, I think we could do something more clever
288 * here.
289 */
290
291 pGC->ops->CopyArea(pSrcDraw, pDstDraw, pGC,
292 0, 0, pDraw->width, pDraw->height, 0, 0);
293
Rob Clarke450d412012-01-08 19:33:48 -0600294 FreeScratchGC(pGC);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500295}
296
297/**
298 * Get current frame count and frame count timestamp, based on drawable's
299 * crtc.
300 */
301static int
Paul Geary8ffd91c2013-04-11 16:03:15 +0100302ARMSOCDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500303{
304 ScreenPtr pScreen = pDraw->pScreen;
305 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100306 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500307 drmVBlank vbl = { .request = {
308 .type = DRM_VBLANK_RELATIVE,
309 .sequence = 0,
310 } };
311 int ret;
312
Paul Geary8ffd91c2013-04-11 16:03:15 +0100313 ret = drmWaitVBlank(pARMSOC->drmFD, &vbl);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500314 if (ret) {
315 static int limit = 5;
316 if (limit) {
Dave Barnish2e998952013-06-11 16:31:10 +0100317 ERROR_MSG("get vblank counter failed: %s",
318 strerror(errno));
Rob Clark4b8f30a2011-08-28 12:51:26 -0500319 limit--;
320 }
321 return FALSE;
322 }
323
Dave Barnish2e998952013-06-11 16:31:10 +0100324 if (ust)
325 *ust = ((CARD64)vbl.reply.tval_sec * 1000000)
326 + vbl.reply.tval_usec;
327
328 if (msc)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500329 *msc = vbl.reply.sequence;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500330
331 return TRUE;
332}
333
Paul Geary8ffd91c2013-04-11 16:03:15 +0100334#define ARMSOC_SWAP_FAKE_FLIP (1 << 0)
335#define ARMSOC_SWAP_FAIL (1 << 1)
John Sheu022833e2012-08-15 11:40:11 -0700336
Dave Barnish2e998952013-06-11 16:31:10 +0100337struct ARMSOCDRISwapCmd {
Rob Clarka6762ef2012-04-12 17:38:39 -0500338 int type;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500339 ClientPtr client;
Rob Clark0bdd3702012-04-20 14:47:51 -0500340 ScreenPtr pScreen;
341 /* Note: store drawable ID, rather than drawable. It's possible that
342 * the drawable can be destroyed while we wait for page flip event:
343 */
344 XID draw_id;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500345 DRI2BufferPtr pDstBuffer;
346 DRI2BufferPtr pSrcBuffer;
347 DRI2SwapEventPtr func;
John Sheu022833e2012-08-15 11:40:11 -0700348 int swapCount;
349 int flags;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500350 void *data;
351};
352
Dave Barnish2e998952013-06-11 16:31:10 +0100353static const char * const swap_names[] = {
Rob Clark0bdd3702012-04-20 14:47:51 -0500354 [DRI2_EXCHANGE_COMPLETE] = "exchange",
355 [DRI2_BLIT_COMPLETE] = "blit",
356 [DRI2_FLIP_COMPLETE] = "flip,"
357};
358
Rob Clark4b8f30a2011-08-28 12:51:26 -0500359void
Dave Barnish2e998952013-06-11 16:31:10 +0100360ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500361{
Rob Clark0bdd3702012-04-20 14:47:51 -0500362 ScreenPtr pScreen = cmd->pScreen;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500363 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100364 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark0bdd3702012-04-20 14:47:51 -0500365 DrawablePtr pDraw = NULL;
366 int status;
Dave Barnish2e998952013-06-11 16:31:10 +0100367 struct ARMSOCPixmapPrivRec *src_priv, *dst_priv;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100368 struct armsoc_bo *old_src_bo, *old_dst_bo;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500369
John Sheu022833e2012-08-15 11:40:11 -0700370 if (--cmd->swapCount > 0)
371 return;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500372
Sean Paul269c9712012-09-04 15:17:33 -0700373 /* Save the old source bo for unreference below */
Dave Barnish2e998952013-06-11 16:31:10 +0100374 src_priv = exaGetPixmapDriverPrivate(
375 ARMSOCBUF(cmd->pSrcBuffer)->pPixmap);
376 dst_priv = exaGetPixmapDriverPrivate(
377 ARMSOCBUF(cmd->pDstBuffer)->pPixmap);
Sean Paul269c9712012-09-04 15:17:33 -0700378 old_src_bo = src_priv->bo;
379 old_dst_bo = dst_priv->bo;
380
Paul Geary8ffd91c2013-04-11 16:03:15 +0100381 if ((cmd->flags & ARMSOC_SWAP_FAIL) == 0) {
John Sheu022833e2012-08-15 11:40:11 -0700382 DEBUG_MSG("%s complete: %d -> %d", swap_names[cmd->type],
Dave Barnish2e998952013-06-11 16:31:10 +0100383 cmd->pSrcBuffer->attachment,
384 cmd->pDstBuffer->attachment);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500385
John Sheu022833e2012-08-15 11:40:11 -0700386 status = dixLookupDrawable(&pDraw, cmd->draw_id, serverClient,
387 M_ANY, DixWriteAccess);
388
389 if (status == Success) {
Dave Barnish2e998952013-06-11 16:31:10 +0100390 if (cmd->type != DRI2_BLIT_COMPLETE &&
391 (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) {
John Sheu022833e2012-08-15 11:40:11 -0700392 assert(cmd->type == DRI2_FLIP_COMPLETE);
Dave Barnish2e998952013-06-11 16:31:10 +0100393 exchangebufs(pDraw, cmd->pSrcBuffer,
394 cmd->pDstBuffer);
John Sheu022833e2012-08-15 11:40:11 -0700395 }
396
397 DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type,
398 cmd->func, cmd->data);
399
Dave Barnish2e998952013-06-11 16:31:10 +0100400 if (cmd->type != DRI2_BLIT_COMPLETE &&
401 (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) {
402 dst_priv = exaGetPixmapDriverPrivate(draw2pix(
403 dri2draw(pDraw, cmd->pDstBuffer)));
John Sheu022833e2012-08-15 11:40:11 -0700404 assert(cmd->type == DRI2_FLIP_COMPLETE);
405 set_scanout_bo(pScrn, dst_priv->bo);
406 }
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100407 }
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100408 }
David Garbett3688b332012-05-11 12:17:34 +0100409
Rob Clark0bdd3702012-04-20 14:47:51 -0500410 /* drop extra refcnt we obtained prior to swap:
411 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100412 ARMSOCDRI2DestroyBuffer(pDraw, cmd->pSrcBuffer);
413 ARMSOCDRI2DestroyBuffer(pDraw, cmd->pDstBuffer);
414 armsoc_bo_unreference(old_src_bo);
415 armsoc_bo_unreference(old_dst_bo);
416 pARMSOC->pending_flips--;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500417
418 free(cmd);
419}
420
421/**
422 * ScheduleSwap is responsible for requesting a DRM vblank event for the
423 * appropriate frame.
424 *
425 * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
426 * the vblank requested can simply be the last queued swap frame + the swap
427 * interval for the drawable.
428 *
429 * In the case of a page flip, we request an event for the last queued swap
430 * frame + swap interval - 1, since we'll need to queue the flip for the frame
431 * immediately following the received event.
432 */
433static int
Paul Geary8ffd91c2013-04-11 16:03:15 +0100434ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500435 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer,
436 CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
437 DRI2SwapEventPtr func, void *data)
438{
439 ScreenPtr pScreen = pDraw->pScreen;
440 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100441 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
442 struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer);
443 struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer);
444 struct ARMSOCDRISwapCmd *cmd = calloc(1, sizeof(*cmd));
David Garbett7d6a6e72012-05-11 11:52:45 +0100445 int src_fb_id, dst_fb_id;
Dave Barnish2e998952013-06-11 16:31:10 +0100446 struct ARMSOCPixmapPrivRec *src_priv, *dst_priv;
Ray Smithedccfd82013-05-31 15:57:12 +0100447 int new_canflip, ret, do_flip;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500448
Dave Barnish2e998952013-06-11 16:31:10 +0100449 if (!cmd)
Paul Geary6fe52f32013-04-03 11:12:24 +0100450 return FALSE;
Paul Geary6fe52f32013-04-03 11:12:24 +0100451
Rob Clark4b8f30a2011-08-28 12:51:26 -0500452 cmd->client = client;
Rob Clark0bdd3702012-04-20 14:47:51 -0500453 cmd->pScreen = pScreen;
454 cmd->draw_id = pDraw->id;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500455 cmd->pSrcBuffer = pSrcBuffer;
456 cmd->pDstBuffer = pDstBuffer;
John Sheu022833e2012-08-15 11:40:11 -0700457 cmd->swapCount = 0;
458 cmd->flags = 0;
Rob Clark4b8f30a2011-08-28 12:51:26 -0500459 cmd->func = func;
460 cmd->data = data;
461
462 DEBUG_MSG("%d -> %d", pSrcBuffer->attachment, pDstBuffer->attachment);
463
Rob Clark0bdd3702012-04-20 14:47:51 -0500464 /* obtain extra ref on buffers to avoid them going away while we await
465 * the page flip event:
466 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100467 ARMSOCDRI2ReferenceBuffer(pSrcBuffer);
468 ARMSOCDRI2ReferenceBuffer(pDstBuffer);
469 pARMSOC->pending_flips++;
Rob Clark0bdd3702012-04-20 14:47:51 -0500470
David Garbett7d6a6e72012-05-11 11:52:45 +0100471 src_priv = exaGetPixmapDriverPrivate(src->pPixmap);
472 dst_priv = exaGetPixmapDriverPrivate(dst->pPixmap);
473
Paul Geary8ffd91c2013-04-11 16:03:15 +0100474 src_fb_id = armsoc_bo_get_fb(src_priv->bo);
475 dst_fb_id = armsoc_bo_get_fb(dst_priv->bo);
David Garbett7d6a6e72012-05-11 11:52:45 +0100476
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100477 new_canflip = canflip(pDraw);
Dave Barnish2e998952013-06-11 16:31:10 +0100478 if ((src->previous_canflip != -1 &&
479 src->previous_canflip != new_canflip) ||
Ray Smithedccfd82013-05-31 15:57:12 +0100480 (dst->previous_canflip != -1 &&
481 dst->previous_canflip != new_canflip)) {
Dave Barnish2e998952013-06-11 16:31:10 +0100482 /* The drawable has transitioned between being flippable and
483 * non-flippable or vice versa. Bump the serial number to force
484 * the DRI2 buffers to be re-allocated during the next frame so
485 * that:
486 * - It is able to be scanned out
487 * (if drawable is now flippable), or
488 * - It is not taking up possibly scarce scanout-able memory
489 * (if drawable is now not flippable)
Raymond Smith4a0c0aa2012-06-20 10:50:39 +0100490 */
491
492 PixmapPtr pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
493 pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER;
494 }
495
496 src->previous_canflip = new_canflip;
497 dst->previous_canflip = new_canflip;
498
Paul Geary8ffd91c2013-04-11 16:03:15 +0100499 armsoc_bo_reference(src_priv->bo);
500 armsoc_bo_reference(dst_priv->bo);
Ray Smithedccfd82013-05-31 15:57:12 +0100501
502 do_flip = src_fb_id && dst_fb_id && canflip(pDraw);
503
504 /* After a resolution change the back buffer (src) will still be of the original size.
505 * We can't sensibly flip to a framebuffer of a different size to the current resolution
506 * (it will look corrupted), so we must do a copy for this frame (which will clip the
507 * contents as expected).
508 *
509 * Once the client calls DRI2GetBuffers again, it will receive a new back buffer of the
510 * same size as the new resolution, and subsequent DRI2SwapBuffers will result in a flip.
511 */
512 do_flip = do_flip && (armsoc_bo_width(src_priv->bo) == armsoc_bo_width(dst_priv->bo));
513 do_flip = do_flip && (armsoc_bo_height(src_priv->bo) == armsoc_bo_height(dst_priv->bo));
514
515 if (do_flip) {
David Garbett7d6a6e72012-05-11 11:52:45 +0100516 DEBUG_MSG("can flip: %d -> %d", src_fb_id, dst_fb_id);
Rob Clarka6762ef2012-04-12 17:38:39 -0500517 cmd->type = DRI2_FLIP_COMPLETE;
Dave Barnish2e998952013-06-11 16:31:10 +0100518 /* TODO: MIDEGL-1461: Handle rollback if multiple CRTC flip is
519 * only partially successful
John Sheu022833e2012-08-15 11:40:11 -0700520 */
521 ret = drmmode_page_flip(pDraw, src_fb_id, cmd);
522
Dave Barnish2e998952013-06-11 16:31:10 +0100523 /* If using page flip events, we'll trigger an immediate
524 * completion in the case that no CRTCs were enabled to be
525 * flipped. If not using page flip events, trigger immediate
526 * completion unconditionally.
John Sheu022833e2012-08-15 11:40:11 -0700527 */
528 if (ret < 0) {
529 /*
530 * Error while flipping; bail.
531 */
Paul Geary8ffd91c2013-04-11 16:03:15 +0100532 cmd->flags |= ARMSOC_SWAP_FAIL;
Ray Smith3c33c3d2013-03-26 16:06:37 +0000533
Dave Barnishde45ed42013-06-05 13:47:56 +0100534 if (pARMSOC->drmmode_interface->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +0000535 cmd->swapCount = -(ret + 1);
536 else
537 cmd->swapCount = 0;
538
John Sheu022833e2012-08-15 11:40:11 -0700539 if (cmd->swapCount == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100540 ARMSOCDRI2SwapComplete(cmd);
Dave Barnish2e998952013-06-11 16:31:10 +0100541
John Sheu022833e2012-08-15 11:40:11 -0700542 return FALSE;
543 } else {
544 if (ret == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100545 cmd->flags |= ARMSOC_SWAP_FAKE_FLIP;
Ray Smith3c33c3d2013-03-26 16:06:37 +0000546
Dave Barnishde45ed42013-06-05 13:47:56 +0100547 if (pARMSOC->drmmode_interface->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +0000548 cmd->swapCount = ret;
549 else
550 cmd->swapCount = 0;
551
John Sheu022833e2012-08-15 11:40:11 -0700552 if (cmd->swapCount == 0)
Paul Geary8ffd91c2013-04-11 16:03:15 +0100553 ARMSOCDRI2SwapComplete(cmd);
John Sheu022833e2012-08-15 11:40:11 -0700554 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500555 } else {
556 /* fallback to blit: */
557 BoxRec box = {
558 .x1 = 0,
559 .y1 = 0,
560 .x2 = pDraw->width,
561 .y2 = pDraw->height,
562 };
563 RegionRec region;
564 RegionInit(&region, &box, 0);
Paul Geary8ffd91c2013-04-11 16:03:15 +0100565 ARMSOCDRI2CopyRegion(pDraw, &region, pDstBuffer, pSrcBuffer);
Rob Clarka6762ef2012-04-12 17:38:39 -0500566 cmd->type = DRI2_BLIT_COMPLETE;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100567 ARMSOCDRI2SwapComplete(cmd);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500568 }
569
570 return TRUE;
571}
572
573/**
574 * Request a DRM event when the requested conditions will be satisfied.
575 *
576 * We need to handle the event and ask the server to wake up the client when
577 * we receive it.
578 */
579static int
Dave Barnish2e998952013-06-11 16:31:10 +0100580ARMSOCDRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr pDraw,
581 CARD64 target_msc, CARD64 divisor, CARD64 remainder)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500582{
583 ScreenPtr pScreen = pDraw->pScreen;
584 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Rob Clark4b8f30a2011-08-28 12:51:26 -0500585
Rob Clark4b8f30a2011-08-28 12:51:26 -0500586 ERROR_MSG("not implemented");
587 return FALSE;
588}
589
590/**
591 * The DRI2 ScreenInit() function.. register our handler fxns w/ DRI2 core
592 */
593Bool
Paul Geary8ffd91c2013-04-11 16:03:15 +0100594ARMSOCDRI2ScreenInit(ScreenPtr pScreen)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500595{
596 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100597 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500598 DRI2InfoRec info = {
Dave Barnish2e998952013-06-11 16:31:10 +0100599 .version = 5,
600 .fd = pARMSOC->drmFD,
601 .driverName = "armsoc",
602 .deviceName = pARMSOC->deviceName,
603 .CreateBuffer = ARMSOCDRI2CreateBuffer,
604 .DestroyBuffer = ARMSOCDRI2DestroyBuffer,
605 .CopyRegion = ARMSOCDRI2CopyRegion,
606 .ScheduleSwap = ARMSOCDRI2ScheduleSwap,
607 .ScheduleWaitMSC = ARMSOCDRI2ScheduleWaitMSC,
608 .GetMSC = ARMSOCDRI2GetMSC,
609 .AuthMagic = drmAuthMagic,
Rob Clark4b8f30a2011-08-28 12:51:26 -0500610 };
611 int minor = 1, major = 0;
612
Dave Barnish2e998952013-06-11 16:31:10 +0100613 if (xf86LoaderCheckSymbol("DRI2Version"))
Rob Clark4b8f30a2011-08-28 12:51:26 -0500614 DRI2Version(&major, &minor);
Rob Clark4b8f30a2011-08-28 12:51:26 -0500615
616 if (minor < 1) {
617 WARNING_MSG("DRI2 requires DRI2 module version 1.1.0 or later");
618 return FALSE;
619 }
620
621 return DRI2ScreenInit(pScreen, &info);
622}
623
624/**
625 * The DRI2 CloseScreen() function.. unregister ourself w/ DRI2 core.
626 */
627void
Paul Geary8ffd91c2013-04-11 16:03:15 +0100628ARMSOCDRI2CloseScreen(ScreenPtr pScreen)
Rob Clark4b8f30a2011-08-28 12:51:26 -0500629{
Rob Clark67b875f2012-04-20 19:13:57 -0500630 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Dave Barnish2e998952013-06-11 16:31:10 +0100631 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Paul Geary8ffd91c2013-04-11 16:03:15 +0100632 while (pARMSOC->pending_flips > 0) {
Rob Clark67b875f2012-04-20 19:13:57 -0500633 DEBUG_MSG("waiting..");
634 drmmode_wait_for_event(pScrn);
635 }
Rob Clark4b8f30a2011-08-28 12:51:26 -0500636 DRI2CloseScreen(pScreen);
637}