dri2ext.c revision 52397711
1/*
2 * Copyright © 2008 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 "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 *   Kristian Høgsberg (krh@redhat.com)
31 */
32
33#ifdef HAVE_XORG_CONFIG_H
34#include <xorg-config.h>
35#endif
36
37#define NEED_REPLIES
38#include <X11/X.h>
39#include <X11/Xproto.h>
40#include <X11/extensions/dri2proto.h>
41#include <X11/extensions/xfixeswire.h>
42#include "dixstruct.h"
43#include "scrnintstr.h"
44#include "pixmapstr.h"
45#include "extnsionst.h"
46#include "xf86drm.h"
47#include "xfixes.h"
48#include "dri2.h"
49
50/* The only xf86 include */
51#include "xf86Module.h"
52
53static ExtensionEntry	*dri2Extension;
54static RESTYPE		 dri2DrawableRes;
55
56static Bool
57validDrawable(ClientPtr client, XID drawable,
58	      DrawablePtr *pDrawable, int *status)
59{
60    *status = dixLookupDrawable(pDrawable, drawable, client, 0, DixReadAccess);
61    if (*status != Success) {
62	client->errorValue = drawable;
63	return FALSE;
64    }
65
66    return TRUE;
67}
68
69static int
70ProcDRI2QueryVersion(ClientPtr client)
71{
72    REQUEST(xDRI2QueryVersionReq);
73    xDRI2QueryVersionReply rep;
74    int n;
75
76    if (client->swapped)
77	swaps(&stuff->length, n);
78
79    REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
80    rep.type = X_Reply;
81    rep.length = 0;
82    rep.sequenceNumber = client->sequence;
83    rep.majorVersion = 1;
84    rep.minorVersion = 1;
85
86    if (client->swapped) {
87    	swaps(&rep.sequenceNumber, n);
88    	swapl(&rep.length, n);
89	swapl(&rep.majorVersion, n);
90	swapl(&rep.minorVersion, n);
91    }
92
93    WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
94
95    return client->noClientException;
96}
97
98static int
99ProcDRI2Connect(ClientPtr client)
100{
101    REQUEST(xDRI2ConnectReq);
102    xDRI2ConnectReply rep;
103    DrawablePtr pDraw;
104    int fd, status;
105    const char *driverName;
106    const char *deviceName;
107
108    REQUEST_SIZE_MATCH(xDRI2ConnectReq);
109    if (!validDrawable(client, stuff->window, &pDraw, &status))
110	return status;
111
112    rep.type = X_Reply;
113    rep.length = 0;
114    rep.sequenceNumber = client->sequence;
115    rep.driverNameLength = 0;
116    rep.deviceNameLength = 0;
117
118    if (!DRI2Connect(pDraw->pScreen,
119		     stuff->driverType, &fd, &driverName, &deviceName))
120	goto fail;
121
122    rep.driverNameLength = strlen(driverName);
123    rep.deviceNameLength = strlen(deviceName);
124    rep.length = (rep.driverNameLength + 3) / 4 +
125	    (rep.deviceNameLength + 3) / 4;
126
127 fail:
128    WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
129    WriteToClient(client, rep.driverNameLength, driverName);
130    WriteToClient(client, rep.deviceNameLength, deviceName);
131
132    return client->noClientException;
133}
134
135static int
136ProcDRI2Authenticate(ClientPtr client)
137{
138    REQUEST(xDRI2AuthenticateReq);
139    xDRI2AuthenticateReply rep;
140    DrawablePtr pDraw;
141    int status;
142
143    REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
144    if (!validDrawable(client, stuff->window, &pDraw, &status))
145	return status;
146
147    rep.type = X_Reply;
148    rep.sequenceNumber = client->sequence;
149    rep.length = 0;
150    rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
151    WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
152
153    return client->noClientException;
154}
155
156static int
157ProcDRI2CreateDrawable(ClientPtr client)
158{
159    REQUEST(xDRI2CreateDrawableReq);
160    DrawablePtr pDrawable;
161    int status;
162
163    REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
164
165    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
166	return status;
167
168    status = DRI2CreateDrawable(pDrawable);
169    if (status != Success)
170	return status;
171
172    if (!AddResource(stuff->drawable, dri2DrawableRes, pDrawable)) {
173	DRI2DestroyDrawable(pDrawable);
174	return BadAlloc;
175    }
176
177    return client->noClientException;
178}
179
180static int
181ProcDRI2DestroyDrawable(ClientPtr client)
182{
183    REQUEST(xDRI2DestroyDrawableReq);
184    DrawablePtr pDrawable;
185    int status;
186
187    REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
188    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
189	return status;
190
191    FreeResourceByType(stuff->drawable, dri2DrawableRes, FALSE);
192
193    return client->noClientException;
194}
195
196
197static void
198send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
199		   DRI2Buffer2Ptr *buffers, int count, int width, int height)
200{
201    xDRI2GetBuffersReply rep;
202    int skip = 0;
203    int i;
204
205    if (pDrawable->type == DRAWABLE_WINDOW) {
206	for (i = 0; i < count; i++) {
207	    /* Do not send the real front buffer of a window to the client.
208	     */
209	    if (buffers[i]->attachment == DRI2BufferFrontLeft) {
210		skip++;
211		continue;
212	    }
213	}
214    }
215
216    rep.type = X_Reply;
217    rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
218    rep.sequenceNumber = client->sequence;
219    rep.width = width;
220    rep.height = height;
221    rep.count = count - skip;
222    WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
223
224    for (i = 0; i < count; i++) {
225	xDRI2Buffer buffer;
226
227	/* Do not send the real front buffer of a window to the client.
228	 */
229	if ((pDrawable->type == DRAWABLE_WINDOW)
230	    && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
231	    continue;
232	}
233
234	buffer.attachment = buffers[i]->attachment;
235	buffer.name = buffers[i]->name;
236	buffer.pitch = buffers[i]->pitch;
237	buffer.cpp = buffers[i]->cpp;
238	buffer.flags = buffers[i]->flags;
239	WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
240    }
241}
242
243
244static int
245ProcDRI2GetBuffers(ClientPtr client)
246{
247    REQUEST(xDRI2GetBuffersReq);
248    DrawablePtr pDrawable;
249    DRI2Buffer2Ptr *buffers;
250    int status, width, height, count;
251    unsigned int *attachments;
252
253    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
254    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
255	return status;
256
257    attachments = (unsigned int *) &stuff[1];
258    buffers = DRI2GetBuffers(pDrawable, &width, &height,
259			     attachments, stuff->count, &count);
260
261
262    send_buffers_reply(client, pDrawable, buffers, count, width, height);
263
264    return client->noClientException;
265}
266
267static int
268ProcDRI2GetBuffersWithFormat(ClientPtr client)
269{
270    REQUEST(xDRI2GetBuffersReq);
271    DrawablePtr pDrawable;
272    DRI2Buffer2Ptr *buffers;
273    int status, width, height, count;
274    unsigned int *attachments;
275
276    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
277    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
278	return status;
279
280    attachments = (unsigned int *) &stuff[1];
281    buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
282				       attachments, stuff->count, &count);
283
284    send_buffers_reply(client, pDrawable, buffers, count, width, height);
285
286    return client->noClientException;
287}
288
289static int
290ProcDRI2CopyRegion(ClientPtr client)
291{
292    REQUEST(xDRI2CopyRegionReq);
293    xDRI2CopyRegionReply rep;
294    DrawablePtr pDrawable;
295    int status;
296    RegionPtr pRegion;
297
298    REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
299
300    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
301	return status;
302
303    VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
304
305    status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
306    if (status != Success)
307	return status;
308
309    /* CopyRegion needs to be a round trip to make sure the X server
310     * queues the swap buffer rendering commands before the DRI client
311     * continues rendering.  The reply has a bitmask to signal the
312     * presense of optional return values as well, but we're not using
313     * that yet.
314     */
315
316    rep.type = X_Reply;
317    rep.length = 0;
318    rep.sequenceNumber = client->sequence;
319
320    WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
321
322    return client->noClientException;
323}
324
325static int
326ProcDRI2Dispatch (ClientPtr client)
327{
328    REQUEST(xReq);
329
330    switch (stuff->data) {
331    case X_DRI2QueryVersion:
332	return ProcDRI2QueryVersion(client);
333    }
334
335    if (!LocalClient(client))
336	return BadRequest;
337
338    switch (stuff->data) {
339    case X_DRI2Connect:
340	return ProcDRI2Connect(client);
341    case X_DRI2Authenticate:
342	return ProcDRI2Authenticate(client);
343    case X_DRI2CreateDrawable:
344	return ProcDRI2CreateDrawable(client);
345    case X_DRI2DestroyDrawable:
346	return ProcDRI2DestroyDrawable(client);
347    case X_DRI2GetBuffers:
348	return ProcDRI2GetBuffers(client);
349    case X_DRI2CopyRegion:
350	return ProcDRI2CopyRegion(client);
351    case X_DRI2GetBuffersWithFormat:
352	return ProcDRI2GetBuffersWithFormat(client);
353    default:
354	return BadRequest;
355    }
356}
357
358static int
359SProcDRI2Connect(ClientPtr client)
360{
361    REQUEST(xDRI2ConnectReq);
362    xDRI2ConnectReply rep;
363    int n;
364
365    /* If the client is swapped, it's not local.  Talk to the hand. */
366
367    swaps(&stuff->length, n);
368    if (sizeof(*stuff) / 4 != client->req_len)
369	return BadLength;
370
371    rep.sequenceNumber = client->sequence;
372    swaps(&rep.sequenceNumber, n);
373    rep.length = 0;
374    rep.driverNameLength = 0;
375    rep.deviceNameLength = 0;
376
377    return client->noClientException;
378}
379
380static int
381SProcDRI2Dispatch (ClientPtr client)
382{
383    REQUEST(xReq);
384
385    /*
386     * Only local clients are allowed DRI access, but remote clients
387     * still need these requests to find out cleanly.
388     */
389    switch (stuff->data)
390    {
391    case X_DRI2QueryVersion:
392	return ProcDRI2QueryVersion(client);
393    case X_DRI2Connect:
394	return SProcDRI2Connect(client);
395    default:
396	return BadRequest;
397    }
398}
399
400static int DRI2DrawableGone(pointer p, XID id)
401{
402    DrawablePtr pDrawable = p;
403
404    DRI2DestroyDrawable(pDrawable);
405
406    return Success;
407}
408
409static void
410DRI2ExtensionInit(void)
411{
412    dri2Extension = AddExtension(DRI2_NAME,
413				 DRI2NumberEvents,
414				 DRI2NumberErrors,
415				 ProcDRI2Dispatch,
416				 SProcDRI2Dispatch,
417				 NULL,
418				 StandardMinorOpcode);
419
420    dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone);
421}
422
423extern Bool noDRI2Extension;
424
425_X_HIDDEN ExtensionModule dri2ExtensionModule = {
426    DRI2ExtensionInit,
427    DRI2_NAME,
428    &noDRI2Extension,
429    NULL,
430    NULL
431};
432