Add patch that contain Mali fixes.
[deb_xorg-server.git] / debian / patches / xorg-server-005-mali_fixes.patch
CommitLineData
47508f2e
JB
1--- a/hw/xfree86/dri2/dri2.c
2+++ b/hw/xfree86/dri2/dri2.c
3@@ -1,4 +1,4 @@
4-/*
5+ /*
6 * Copyright © 2007, 2008 Red Hat, Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9@@ -100,6 +100,7 @@ typedef struct _DRI2Drawable {
10 CARD64 last_swap_ust; /* ust at completion of most recent swap */
11 int swap_limit; /* for N-buffering */
12 Bool needInvalidate;
13+ Bool client_created;
14 int prime_id;
15 PixmapPtr prime_slave_pixmap;
16 PixmapPtr redirectpixmap;
17@@ -114,6 +115,7 @@ typedef struct _DRI2Screen {
18 int fd;
19 unsigned int lastSequence;
20 int prime_id;
21+ Bool need_async_swapbuffers_reply;
22
23 DRI2CreateBufferProcPtr CreateBuffer;
24 DRI2DestroyBufferProcPtr DestroyBuffer;
25@@ -201,6 +203,7 @@ DRI2AllocateDrawable(DrawablePtr pDraw)
26 if (pPriv == NULL)
27 return NULL;
28
29+ pPriv->client_created = FALSE;
30 pPriv->dri2_screen = ds;
31 pPriv->drawable = pDraw;
32 pPriv->width = pDraw->width;
33@@ -328,6 +331,15 @@ DRI2CreateDrawable2(ClientPtr client, Dr
34 int rc;
35
36 pPriv = DRI2GetDrawable(pDraw);
37+ if (pPriv && dri2_id_out == NULL && pPriv->client_created) {
38+ /* We already allocated a DRI2Drawable for this drawable, the client
39+ * has called into this function (so will receive invalidate events)
40+ * and now we're being called by the client again (we know this because
41+ * the caller doesn't care about the dri2_id). This means we don't need
42+ * to allocate another one, we have nothing else to do. */
43+ pPriv->prime_id = dri2_client->prime_id;
44+ return Success;
45+ }
46 if (pPriv == NULL)
47 pPriv = DRI2AllocateDrawable(pDraw);
48 if (pPriv == NULL)
49@@ -342,6 +354,11 @@ DRI2CreateDrawable2(ClientPtr client, Dr
50
51 if (dri2_id_out)
52 *dri2_id_out = dri2_id;
53+ else {
54+ /* The client has called in for the first time, it will now receive
55+ * invalidate events. Record this for later. */
56+ pPriv->client_created = TRUE;
57+ }
58
59 return Success;
60 }
61@@ -1071,7 +1088,11 @@ DRI2WaitSwap(ClientPtr client, DrawableP
62 return FALSE;
63 }
64
65-
66+Bool
67+DRI2NeedAsyncSwapBuffersReply(DrawablePtr pDraw)
68+{
69+ return DRI2GetScreen(pDraw->pScreen)->need_async_swapbuffers_reply;
70+}
71
72 int
73 DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
74@@ -1516,6 +1537,12 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2In
75 if (!ds->driverNames)
76 goto err_out;
77 ds->driverNames[0] = info->driverName;
78+
79+ /* Mali incorrectly assumes that a return from SwapBuffers means that
80+ * buffers have been swapped, it doesn't wait for the relevant event.
81+ * In this case, we work around this annoyance by delaying the
82+ * SwapBuffers reply until the swap has actually completed. */
83+ ds->need_async_swapbuffers_reply = strcmp(info->driverName, "armsoc") == 0;
84 }
85 else {
86 ds->numDrivers = info->numDrivers;
87--- a/hw/xfree86/dri2/dri2ext.c
88+++ b/hw/xfree86/dri2/dri2ext.c
89@@ -53,6 +53,14 @@
90
91 static int DRI2EventBase;
92
93+/* Data shared by ProcDRI2SwapBuffers and the asynchronous callback
94+ * DRI2SwapEvent */
95+struct SwapBuffersData {
96+ CARD64 swap_target;
97+ int refcnt;
98+ DrawablePtr pDrawable;
99+ CARD16 sequence;
100+};
101
102 static Bool
103 validDrawable(ClientPtr client, XID drawable, Mask access_mode,
104@@ -276,7 +284,6 @@ ProcDRI2GetBuffers(ClientPtr client)
105
106 if (DRI2ThrottleClient(client, pDrawable))
107 return Success;
108-
109 attachments = (unsigned int *) &stuff[1];
110 buffers = DRI2GetBuffers(pDrawable, &width, &height,
111 attachments, stuff->count, &count);
112@@ -355,6 +362,24 @@ load_swap_reply(xDRI2SwapBuffersReply *
113 rep->swap_lo = sbc & 0xffffffff;
114 }
115
116+static void swap_buffers_data_unref(struct SwapBuffersData *data)
117+{
118+ if (--data->refcnt == 0)
119+ free(data);
120+}
121+
122+static void send_swap_buffers_reply(ClientPtr client, struct SwapBuffersData *data)
123+{
124+ xDRI2SwapBuffersReply rep = {
125+ .type = X_Reply,
126+ .length = 0,
127+ .sequenceNumber = data->sequence,
128+ };
129+
130+ load_swap_reply(&rep, data->swap_target);
131+ WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
132+}
133+
134 static CARD64
135 vals_to_card64(CARD32 lo, CARD32 hi)
136 {
137@@ -365,11 +390,11 @@ static void
138 DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
139 CARD32 sbc)
140 {
141- DrawablePtr pDrawable = data;
142+ struct SwapBuffersData *sbdata = data;
143 xDRI2BufferSwapComplete2 event = {
144 .type = DRI2EventBase + DRI2_BufferSwapComplete,
145 .event_type = type,
146- .drawable = pDrawable->id,
147+ .drawable = sbdata->pDrawable->id,
148 .ust_hi = (CARD64) ust >> 32,
149 .ust_lo = ust & 0xffffffff,
150 .msc_hi = (CARD64) msc >> 32,
151@@ -377,6 +402,12 @@ DRI2SwapEvent(ClientPtr client, void *da
152 .sbc = sbc
153 };
154
155+ if (DRI2NeedAsyncSwapBuffersReply(sbdata->pDrawable)) {
156+ send_swap_buffers_reply(client, sbdata);
157+ AttendClient(client);
158+ }
159+
160+ swap_buffers_data_unref(data);
161 WriteEventsToClient(client, 1, (xEvent *) &event);
162 }
163
164@@ -384,14 +415,11 @@ static int
165 ProcDRI2SwapBuffers(ClientPtr client)
166 {
167 REQUEST(xDRI2SwapBuffersReq);
168- xDRI2SwapBuffersReply rep = {
169- .type = X_Reply,
170- .sequenceNumber = client->sequence,
171- .length = 0
172- };
173 DrawablePtr pDrawable;
174- CARD64 target_msc, divisor, remainder, swap_target;
175+ CARD64 target_msc, divisor, remainder;
176+ struct SwapBuffersData *data;
177 int status;
178+ Bool need_async_swap_reply;
179
180 REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
181
182@@ -399,6 +427,8 @@ ProcDRI2SwapBuffers(ClientPtr client)
183 DixReadAccess | DixWriteAccess, &pDrawable, &status))
184 return status;
185
186+ need_async_swap_reply = DRI2NeedAsyncSwapBuffersReply(pDrawable);
187+
188 /*
189 * Ensures an out of control client can't exhaust our swap queue, and
190 * also orders swaps.
191@@ -406,18 +436,49 @@ ProcDRI2SwapBuffers(ClientPtr client)
192 if (DRI2ThrottleClient(client, pDrawable))
193 return Success;
194
195+ data = malloc(sizeof(struct SwapBuffersData));
196+ /* DRI2SwapEvent() above might feel like the obvious place to free the
197+ * data struct we just allocated. But consider the following sequence of
198+ * events (and understand that swap_target is stored in data):
199+ * 1. DRI2SwapBuffers accesses swap_target
200+ * 2. DRI2SwapBuffers calls into ScheduleSwap
201+ * 3. ScheduleSwap blits and calls DRI2SwapEvent before returning
202+ * 4. Back in DRI2SwapBuffers, we access swap_target again
203+ *
204+ * If we had freed data in step 3, we would have a use-after-free in
205+ * step 4.
206+ *
207+ * So, we set up a refcount of 2. One ref is owned by this function, and
208+ * one ref is owned by DRI2SwapEvent. We only free the data once both
209+ * functions are done. */
210+ data->refcnt = 2;
211+ data->pDrawable = pDrawable;
212+ data->sequence = client->sequence;
213+
214 target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
215 divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
216 remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
217
218+ /* If we're sending the reply later, we need to avoid processing any
219+ * more requests from this client until that point. */
220+ if (need_async_swap_reply)
221+ IgnoreClient(client);
222+
223 status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
224- &swap_target, DRI2SwapEvent, pDrawable);
225- if (status != Success)
226+ &data->swap_target, DRI2SwapEvent, data);
227+
228+ if (status != Success) {
229+ swap_buffers_data_unref(data);
230+ swap_buffers_data_unref(data);
231+ if (need_async_swap_reply)
232+ AttendClient(client);
233 return BadDrawable;
234+ }
235
236- load_swap_reply(&rep, swap_target);
237+ if (!need_async_swap_reply)
238+ send_swap_buffers_reply(client, data);
239
240- WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
241+ swap_buffers_data_unref(data);
242
243 return Success;
244 }
245--- a/hw/xfree86/dri2/dri2.h
246+++ b/hw/xfree86/dri2/dri2.h
247@@ -359,4 +359,6 @@ extern _X_EXPORT int DRI2GetParam(Client
248 CARD64 *value);
249
250 extern _X_EXPORT DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest);
251+
252+extern Bool DRI2NeedAsyncSwapBuffersReply(DrawablePtr pDraw);
253 #endif