d13830e4e49a22091a14c89a5ec003d7f7e9afc0
[mesa.git] / src / glx / x11 / glx_pbuffer.c
1 /*
2 * (C) Copyright IBM Corporation 2004
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file glx_pbuffer.c
27 * Implementation of pbuffer related functions.
28 *
29 * \author Ian Romanick <idr@us.ibm.com>
30 */
31
32 #include <inttypes.h>
33 #include "glxclient.h"
34 #include <X11/extensions/extutil.h>
35 #include <X11/extensions/Xext.h>
36 #include <assert.h>
37 #include <string.h>
38 #include "glapi.h"
39 #include "glxextensions.h"
40 #include "glcontextmodes.h"
41 #include "glheader.h"
42
43 static void ChangeDrawableAttribute( Display * dpy, GLXDrawable drawable,
44 const CARD32 * attribs, size_t num_attribs );
45
46 static void DestroyPbuffer( Display * dpy, GLXDrawable drawable );
47
48 static GLXDrawable CreatePbuffer( Display *dpy,
49 const __GLcontextModes * fbconfig, unsigned int width, unsigned int height,
50 const int *attrib_list, GLboolean size_in_attribs );
51
52 static int GetDrawableAttribute( Display *dpy, GLXDrawable drawable,
53 int attribute, unsigned int *value );
54
55
56 /**
57 * Change a drawable's attribute.
58 *
59 * This function is used to implement \c glXSelectEvent and
60 * \c glXSelectEventSGIX.
61 *
62 * \note
63 * This function dynamically determines whether to use the SGIX_pbuffer
64 * version of the protocol or the GLX 1.3 version of the protocol.
65 *
66 * \todo
67 * This function needs to be modified to work with direct-rendering drivers.
68 */
69 static void
70 ChangeDrawableAttribute( Display * dpy, GLXDrawable drawable,
71 const CARD32 * attribs, size_t num_attribs )
72 {
73 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
74 CARD32 * output;
75 CARD8 opcode;
76
77 if ( (dpy == NULL) || (drawable == 0) ) {
78 return;
79 }
80
81 opcode = __glXSetupForCommand(dpy);
82 if (!opcode)
83 return;
84
85 LockDisplay(dpy);
86
87 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
88 xGLXChangeDrawableAttributesReq *req;
89
90 GetReqExtra( GLXChangeDrawableAttributes, 8 + (8 * num_attribs), req );
91 output = (CARD32 *) (req + 1);
92
93 req->reqType = opcode;
94 req->glxCode = X_GLXChangeDrawableAttributes;
95 req->drawable = drawable;
96 req->numAttribs = (CARD32) num_attribs;
97 }
98 else {
99 xGLXVendorPrivateWithReplyReq *vpreq;
100
101 GetReqExtra( GLXVendorPrivateWithReply, 4 + (8 * num_attribs), vpreq );
102 output = (CARD32 *) (vpreq + 1);
103
104 vpreq->reqType = opcode;
105 vpreq->glxCode = X_GLXVendorPrivateWithReply;
106 vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX;
107
108 output[0] = (CARD32) drawable;
109 output++;
110 }
111
112 (void) memcpy( output, attribs, sizeof( CARD32 ) * 2 * num_attribs );
113
114 UnlockDisplay(dpy);
115 SyncHandle();
116
117 return;
118 }
119
120
121 /**
122 * Destroy a pbuffer.
123 *
124 * This function is used to implement \c glXDestroyPbuffer and
125 * \c glXDestroyGLXPbufferSGIX.
126 *
127 * \note
128 * This function dynamically determines whether to use the SGIX_pbuffer
129 * version of the protocol or the GLX 1.3 version of the protocol.
130 *
131 * \todo
132 * This function needs to be modified to work with direct-rendering drivers.
133 */
134 static void
135 DestroyPbuffer( Display * dpy, GLXDrawable drawable )
136 {
137 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
138 CARD8 opcode;
139
140 if ( (dpy == NULL) || (drawable == 0) ) {
141 return;
142 }
143
144 opcode = __glXSetupForCommand(dpy);
145 if (!opcode)
146 return;
147
148 LockDisplay(dpy);
149
150 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
151 xGLXDestroyPbufferReq * req;
152
153 GetReq( GLXDestroyPbuffer, req );
154 req->reqType = opcode;
155 req->glxCode = X_GLXDestroyPbuffer;
156 req->pbuffer = (GLXPbuffer) drawable;
157 }
158 else {
159 xGLXVendorPrivateWithReplyReq *vpreq;
160 CARD32 * data;
161
162 GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
163 data = (CARD32 *) (vpreq + 1);
164
165 data[0] = (CARD32) drawable;
166
167 vpreq->reqType = opcode;
168 vpreq->glxCode = X_GLXVendorPrivateWithReply;
169 vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
170 }
171
172 UnlockDisplay(dpy);
173 SyncHandle();
174
175 return;
176 }
177
178
179 /**
180 * Get a drawable's attribute.
181 *
182 * This function is used to implement \c glXGetSelectedEvent and
183 * \c glXGetSelectedEventSGIX.
184 *
185 * \note
186 * This function dynamically determines whether to use the SGIX_pbuffer
187 * version of the protocol or the GLX 1.3 version of the protocol.
188 *
189 * \todo
190 * The number of attributes returned is likely to be small, probably less than
191 * 10. Given that, this routine should try to use an array on the stack to
192 * capture the reply rather than always calling Xmalloc.
193 *
194 * \todo
195 * This function needs to be modified to work with direct-rendering drivers.
196 */
197 static int
198 GetDrawableAttribute( Display *dpy, GLXDrawable drawable,
199 int attribute, unsigned int *value )
200 {
201 __GLXdisplayPrivate *priv;
202 xGLXGetDrawableAttributesReply reply;
203 CARD32 * data;
204 CARD8 opcode;
205 unsigned int length;
206 unsigned int i;
207 unsigned int num_attributes;
208
209 if ( (dpy == NULL) || (drawable == 0) ) {
210 return 0;
211 }
212
213 priv = __glXInitialize(dpy);
214 GLboolean use_glx_1_3 = ((priv->majorVersion > 1)
215 || (priv->minorVersion >= 3));
216
217 *value = 0;
218
219
220 opcode = __glXSetupForCommand(dpy);
221 if (!opcode)
222 return 0;
223
224 LockDisplay(dpy);
225
226 if ( use_glx_1_3 ) {
227 xGLXGetDrawableAttributesReq *req;
228
229 GetReqExtra( GLXGetDrawableAttributes, 4, req );
230 req->reqType = opcode;
231 req->glxCode = X_GLXGetDrawableAttributes;
232 req->drawable = drawable;
233 }
234 else {
235 xGLXVendorPrivateWithReplyReq *vpreq;
236
237 GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
238 data = (CARD32 *) (vpreq + 1);
239 data[0] = (CARD32) drawable;
240
241 vpreq->reqType = opcode;
242 vpreq->glxCode = X_GLXVendorPrivateWithReply;
243 vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
244 }
245
246 _XReply(dpy, (xReply*) &reply, 0, False);
247
248 if (reply.type == X_Error)
249 {
250 UnlockDisplay(dpy);
251 SyncHandle();
252 return 0;
253 }
254
255 length = reply.length;
256 if (length)
257 {
258 num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
259 data = (CARD32 *) Xmalloc( length * sizeof(CARD32) );
260 if ( data == NULL ) {
261 /* Throw data on the floor */
262 _XEatData(dpy, length);
263 } else {
264 _XRead(dpy, (char *)data, length * sizeof(CARD32) );
265
266 /* Search the set of returned attributes for the attribute requested by
267 * the caller.
268 */
269 for ( i = 0 ; i < num_attributes ; i++ ) {
270 if ( data[i*2] == attribute ) {
271 *value = data[ (i*2) + 1 ];
272 break;
273 }
274 }
275
276 Xfree( data );
277 }
278 }
279
280 UnlockDisplay(dpy);
281 SyncHandle();
282
283 return 0;
284 }
285
286
287 /**
288 * Create a non-pbuffer GLX drawable.
289 *
290 * \todo
291 * This function needs to be modified to work with direct-rendering drivers.
292 */
293 static GLXDrawable
294 CreateDrawable( Display *dpy, const __GLcontextModes * fbconfig,
295 Drawable drawable, const int *attrib_list,
296 CARD8 glxCode )
297 {
298 xGLXCreateWindowReq * req;
299 CARD32 * data;
300 unsigned int i;
301 CARD8 opcode;
302
303 i = 0;
304 if (attrib_list) {
305 while (attrib_list[i * 2] != None)
306 i++;
307 }
308
309 opcode = __glXSetupForCommand(dpy);
310 if (!opcode)
311 return None;
312
313 LockDisplay(dpy);
314 GetReqExtra( GLXCreateWindow, 8 * i, req );
315 data = (CARD32 *) (req + 1);
316
317 req->reqType = opcode;
318 req->glxCode = glxCode;
319 req->screen = (CARD32) fbconfig->screen;
320 req->fbconfig = fbconfig->fbconfigID;
321 req->window = (GLXPbuffer) drawable;
322 req->glxwindow = (GLXWindow) XAllocID(dpy);
323 req->numAttribs = (CARD32) i;
324
325 memcpy( data, attrib_list, 8 * i );
326
327 UnlockDisplay(dpy);
328 SyncHandle();
329
330 return (GLXDrawable)req->glxwindow;
331 }
332
333
334 /**
335 * Destroy a non-pbuffer GLX drawable.
336 *
337 * \todo
338 * This function needs to be modified to work with direct-rendering drivers.
339 */
340 static void
341 DestroyDrawable( Display * dpy, GLXDrawable drawable, CARD32 glxCode )
342 {
343 xGLXDestroyPbufferReq * req;
344 CARD8 opcode;
345
346 if ( (dpy == NULL) || (drawable == 0) ) {
347 return;
348 }
349
350
351 opcode = __glXSetupForCommand(dpy);
352 if (!opcode)
353 return;
354
355 LockDisplay(dpy);
356
357 GetReqExtra( GLXDestroyPbuffer, 4, req );
358 req->reqType = opcode;
359 req->glxCode = glxCode;
360 req->pbuffer = (GLXPbuffer) drawable;
361
362 UnlockDisplay(dpy);
363 SyncHandle();
364
365 return;
366 }
367
368
369 /**
370 * Create a pbuffer.
371 *
372 * This function is used to implement \c glXCreatePbuffer and
373 * \c glXCreateGLXPbufferSGIX.
374 *
375 * \note
376 * This function dynamically determines whether to use the SGIX_pbuffer
377 * version of the protocol or the GLX 1.3 version of the protocol.
378 *
379 * \todo
380 * This function needs to be modified to work with direct-rendering drivers.
381 */
382 static GLXDrawable
383 CreatePbuffer( Display *dpy, const __GLcontextModes * fbconfig,
384 unsigned int width, unsigned int height,
385 const int *attrib_list, GLboolean size_in_attribs )
386 {
387 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
388 GLXDrawable id = 0;
389 CARD32 * data;
390 CARD8 opcode;
391 unsigned int i;
392
393 i = 0;
394 if (attrib_list) {
395 while (attrib_list[i * 2])
396 i++;
397 }
398
399 opcode = __glXSetupForCommand(dpy);
400 if (!opcode)
401 return None;
402
403 LockDisplay(dpy);
404 id = XAllocID(dpy);
405
406 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
407 xGLXCreatePbufferReq * req;
408 unsigned int extra = (size_in_attribs) ? 0 : 2;
409
410 GetReqExtra( GLXCreatePbuffer, (8 * (i + extra)), req );
411 data = (CARD32 *) (req + 1);
412
413 req->reqType = opcode;
414 req->glxCode = X_GLXCreatePbuffer;
415 req->screen = (CARD32) fbconfig->screen;
416 req->fbconfig = fbconfig->fbconfigID;
417 req->pbuffer = (GLXPbuffer) id;
418 req->numAttribs = (CARD32) (i + extra);
419
420 if ( ! size_in_attribs ) {
421 data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
422 data[(2 * i) + 1] = width;
423 data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
424 data[(2 * i) + 3] = height;
425 data += 4;
426 }
427 }
428 else {
429 xGLXVendorPrivateReq *vpreq;
430
431 GetReqExtra( GLXVendorPrivate, 20 + (8 * i), vpreq );
432 data = (CARD32 *) (vpreq + 1);
433
434 vpreq->reqType = opcode;
435 vpreq->glxCode = X_GLXVendorPrivate;
436 vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
437
438 data[0] = (CARD32) fbconfig->screen;
439 data[1] = (CARD32) fbconfig->fbconfigID;
440 data[2] = (CARD32) id;
441 data[3] = (CARD32) width;
442 data[4] = (CARD32) height;
443 data += 5;
444 }
445
446 (void) memcpy( data, attrib_list, sizeof(CARD32) * 2 * i );
447
448 UnlockDisplay(dpy);
449 SyncHandle();
450
451 return id;
452 }
453
454
455 /**
456 * Create a new pbuffer.
457 */
458 PUBLIC GLXPbufferSGIX
459 glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config,
460 unsigned int width, unsigned int height,
461 int *attrib_list)
462 {
463 return (GLXPbufferSGIX) CreatePbuffer( dpy, (__GLcontextModes *) config,
464 width, height,
465 attrib_list, GL_FALSE );
466 }
467
468
469 /**
470 * Create a new pbuffer.
471 */
472 PUBLIC GLXPbuffer
473 glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attrib_list)
474 {
475 return (GLXPbuffer) CreatePbuffer( dpy, (__GLcontextModes *) config,
476 0, 0,
477 attrib_list, GL_TRUE );
478 }
479
480
481 /**
482 * Destroy an existing pbuffer.
483 */
484 PUBLIC void
485 glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
486 {
487 DestroyPbuffer( dpy, pbuf );
488 }
489
490
491 /**
492 * Query an attribute of a drawable.
493 */
494 PUBLIC void
495 glXQueryDrawable(Display *dpy, GLXDrawable drawable,
496 int attribute, unsigned int *value)
497 {
498 GetDrawableAttribute( dpy, drawable, attribute, value );
499 }
500
501
502 /**
503 * Query an attribute of a pbuffer.
504 */
505 PUBLIC int
506 glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX drawable,
507 int attribute, unsigned int *value)
508 {
509 return GetDrawableAttribute( dpy, drawable, attribute, value );
510 }
511
512
513 /**
514 * Select the event mask for a drawable.
515 */
516 PUBLIC void
517 glXSelectEvent(Display *dpy, GLXDrawable drawable, unsigned long mask)
518 {
519 CARD32 attribs[2];
520
521 attribs[0] = (CARD32) GLX_EVENT_MASK;
522 attribs[1] = (CARD32) mask;
523
524 ChangeDrawableAttribute( dpy, drawable, attribs, 1 );
525 }
526
527
528 /**
529 * Get the selected event mask for a drawable.
530 */
531 PUBLIC void
532 glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask)
533 {
534 unsigned int value;
535
536
537 /* The non-sense with value is required because on LP64 platforms
538 * sizeof(unsigned int) != sizeof(unsigned long). On little-endian
539 * we could just type-cast the pointer, but why?
540 */
541
542 GetDrawableAttribute( dpy, drawable, GLX_EVENT_MASK_SGIX, & value );
543 *mask = value;
544 }
545
546
547 PUBLIC GLXPixmap
548 glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap,
549 const int *attrib_list )
550 {
551 return CreateDrawable( dpy, (__GLcontextModes *) config,
552 (Drawable) pixmap, attrib_list,
553 X_GLXCreatePixmap );
554 }
555
556
557 PUBLIC GLXWindow
558 glXCreateWindow( Display *dpy, GLXFBConfig config, Window win,
559 const int *attrib_list )
560 {
561 return CreateDrawable( dpy, (__GLcontextModes *) config,
562 (Drawable) win, attrib_list,
563 X_GLXCreateWindow );
564 }
565
566
567 PUBLIC void
568 glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
569 {
570 DestroyDrawable( dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap );
571 }
572
573
574 PUBLIC void
575 glXDestroyWindow(Display *dpy, GLXWindow win)
576 {
577 DestroyDrawable( dpy, (GLXDrawable) win, X_GLXDestroyWindow );
578 }
579
580
581 PUBLIC GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
582 (Display *dpy, GLXPbufferSGIX pbuf),
583 (dpy, pbuf),
584 glXDestroyPbuffer)
585
586 PUBLIC GLX_ALIAS_VOID(glXSelectEventSGIX,
587 (Display *dpy, GLXDrawable drawable, unsigned long mask),
588 (dpy, drawable, mask),
589 glXSelectEvent)
590
591 PUBLIC GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
592 (Display *dpy, GLXDrawable drawable, unsigned long *mask),
593 (dpy, drawable, mask),
594 glXGetSelectedEvent)