DRI interface changes and DRI2 direct rendering support.
[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
44 /**
45 * Change a drawable's attribute.
46 *
47 * This function is used to implement \c glXSelectEvent and
48 * \c glXSelectEventSGIX.
49 *
50 * \note
51 * This function dynamically determines whether to use the SGIX_pbuffer
52 * version of the protocol or the GLX 1.3 version of the protocol.
53 *
54 * \todo
55 * This function needs to be modified to work with direct-rendering drivers.
56 */
57 static void
58 ChangeDrawableAttribute( Display * dpy, GLXDrawable drawable,
59 const CARD32 * attribs, size_t num_attribs )
60 {
61 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
62 CARD32 * output;
63 CARD8 opcode;
64
65 if ( (dpy == NULL) || (drawable == 0) ) {
66 return;
67 }
68
69 opcode = __glXSetupForCommand(dpy);
70 if (!opcode)
71 return;
72
73 LockDisplay(dpy);
74
75 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
76 xGLXChangeDrawableAttributesReq *req;
77
78 GetReqExtra( GLXChangeDrawableAttributes, 8 + (8 * num_attribs), req );
79 output = (CARD32 *) (req + 1);
80
81 req->reqType = opcode;
82 req->glxCode = X_GLXChangeDrawableAttributes;
83 req->drawable = drawable;
84 req->numAttribs = (CARD32) num_attribs;
85 }
86 else {
87 xGLXVendorPrivateWithReplyReq *vpreq;
88
89 GetReqExtra( GLXVendorPrivateWithReply, 4 + (8 * num_attribs), vpreq );
90 output = (CARD32 *) (vpreq + 1);
91
92 vpreq->reqType = opcode;
93 vpreq->glxCode = X_GLXVendorPrivateWithReply;
94 vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX;
95
96 output[0] = (CARD32) drawable;
97 output++;
98 }
99
100 (void) memcpy( output, attribs, sizeof( CARD32 ) * 2 * num_attribs );
101
102 UnlockDisplay(dpy);
103 SyncHandle();
104
105 return;
106 }
107
108
109 /**
110 * Destroy a pbuffer.
111 *
112 * This function is used to implement \c glXDestroyPbuffer and
113 * \c glXDestroyGLXPbufferSGIX.
114 *
115 * \note
116 * This function dynamically determines whether to use the SGIX_pbuffer
117 * version of the protocol or the GLX 1.3 version of the protocol.
118 *
119 * \todo
120 * This function needs to be modified to work with direct-rendering drivers.
121 */
122 static void
123 DestroyPbuffer( Display * dpy, GLXDrawable drawable )
124 {
125 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
126 CARD8 opcode;
127
128 if ( (dpy == NULL) || (drawable == 0) ) {
129 return;
130 }
131
132 opcode = __glXSetupForCommand(dpy);
133 if (!opcode)
134 return;
135
136 LockDisplay(dpy);
137
138 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
139 xGLXDestroyPbufferReq * req;
140
141 GetReq( GLXDestroyPbuffer, req );
142 req->reqType = opcode;
143 req->glxCode = X_GLXDestroyPbuffer;
144 req->pbuffer = (GLXPbuffer) drawable;
145 }
146 else {
147 xGLXVendorPrivateWithReplyReq *vpreq;
148 CARD32 * data;
149
150 GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
151 data = (CARD32 *) (vpreq + 1);
152
153 data[0] = (CARD32) drawable;
154
155 vpreq->reqType = opcode;
156 vpreq->glxCode = X_GLXVendorPrivateWithReply;
157 vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
158 }
159
160 UnlockDisplay(dpy);
161 SyncHandle();
162
163 return;
164 }
165
166
167 /**
168 * Get a drawable's attribute.
169 *
170 * This function is used to implement \c glXGetSelectedEvent and
171 * \c glXGetSelectedEventSGIX.
172 *
173 * \note
174 * This function dynamically determines whether to use the SGIX_pbuffer
175 * version of the protocol or the GLX 1.3 version of the protocol.
176 *
177 * \todo
178 * The number of attributes returned is likely to be small, probably less than
179 * 10. Given that, this routine should try to use an array on the stack to
180 * capture the reply rather than always calling Xmalloc.
181 *
182 * \todo
183 * This function needs to be modified to work with direct-rendering drivers.
184 */
185 static int
186 GetDrawableAttribute( Display *dpy, GLXDrawable drawable,
187 int attribute, unsigned int *value )
188 {
189 __GLXdisplayPrivate *priv;
190 xGLXGetDrawableAttributesReply reply;
191 CARD32 * data;
192 CARD8 opcode;
193 unsigned int length;
194 unsigned int i;
195 unsigned int num_attributes;
196
197 if ( (dpy == NULL) || (drawable == 0) ) {
198 return 0;
199 }
200
201 priv = __glXInitialize(dpy);
202 GLboolean use_glx_1_3 = ((priv->majorVersion > 1)
203 || (priv->minorVersion >= 3));
204
205 *value = 0;
206
207
208 opcode = __glXSetupForCommand(dpy);
209 if (!opcode)
210 return 0;
211
212 LockDisplay(dpy);
213
214 if ( use_glx_1_3 ) {
215 xGLXGetDrawableAttributesReq *req;
216
217 GetReqExtra( GLXGetDrawableAttributes, 4, req );
218 req->reqType = opcode;
219 req->glxCode = X_GLXGetDrawableAttributes;
220 req->drawable = drawable;
221 }
222 else {
223 xGLXVendorPrivateWithReplyReq *vpreq;
224
225 GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
226 data = (CARD32 *) (vpreq + 1);
227 data[0] = (CARD32) drawable;
228
229 vpreq->reqType = opcode;
230 vpreq->glxCode = X_GLXVendorPrivateWithReply;
231 vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
232 }
233
234 _XReply(dpy, (xReply*) &reply, 0, False);
235
236 if (reply.type == X_Error)
237 {
238 UnlockDisplay(dpy);
239 SyncHandle();
240 return 0;
241 }
242
243 length = reply.length;
244 if (length)
245 {
246 num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
247 data = (CARD32 *) Xmalloc( length * sizeof(CARD32) );
248 if ( data == NULL ) {
249 /* Throw data on the floor */
250 _XEatData(dpy, length);
251 } else {
252 _XRead(dpy, (char *)data, length * sizeof(CARD32) );
253
254 /* Search the set of returned attributes for the attribute requested by
255 * the caller.
256 */
257 for ( i = 0 ; i < num_attributes ; i++ ) {
258 if ( data[i*2] == attribute ) {
259 *value = data[ (i*2) + 1 ];
260 break;
261 }
262 }
263
264 Xfree( data );
265 }
266 }
267
268 UnlockDisplay(dpy);
269 SyncHandle();
270
271 return 0;
272 }
273
274 #ifdef GLX_DIRECT_RENDERING
275 extern __GLXDRIdrawable *
276 GetGLXDRIDrawable(Display *dpy, GLXDrawable drawable, int * const scrn_num);
277
278 static GLenum
279 determineTextureTarget(const int *attribs, int numAttribs)
280 {
281 GLenum target = 0;
282 int i;
283
284 for (i = 0; i < numAttribs; i++) {
285 if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) {
286 switch (attribs[2 * i + 1]) {
287 case GLX_TEXTURE_2D_EXT:
288 target = GL_TEXTURE_2D;
289 break;
290 case GLX_TEXTURE_RECTANGLE_EXT:
291 target = GL_TEXTURE_RECTANGLE_ARB;
292 break;
293 }
294 }
295 }
296
297 return target;
298 }
299 #endif
300
301 /**
302 * Create a non-pbuffer GLX drawable.
303 *
304 * \todo
305 * This function needs to be modified to work with direct-rendering drivers.
306 */
307 static GLXDrawable
308 CreateDrawable( Display *dpy, const __GLcontextModes * fbconfig,
309 Drawable drawable, const int *attrib_list,
310 CARD8 glxCode )
311 {
312 xGLXCreateWindowReq * req;
313 CARD32 * data;
314 unsigned int i;
315 CARD8 opcode;
316
317 i = 0;
318 if (attrib_list) {
319 while (attrib_list[i * 2] != None)
320 i++;
321 }
322
323 opcode = __glXSetupForCommand(dpy);
324 if (!opcode)
325 return None;
326
327 LockDisplay(dpy);
328 GetReqExtra( GLXCreateWindow, 8 * i, req );
329 data = (CARD32 *) (req + 1);
330
331 req->reqType = opcode;
332 req->glxCode = glxCode;
333 req->screen = (CARD32) fbconfig->screen;
334 req->fbconfig = fbconfig->fbconfigID;
335 req->window = (CARD32) drawable;
336 req->glxwindow = (GLXWindow) XAllocID(dpy);
337 req->numAttribs = (CARD32) i;
338
339 memcpy( data, attrib_list, 8 * i );
340
341 UnlockDisplay(dpy);
342 SyncHandle();
343
344 #ifdef GLX_DIRECT_RENDERING
345 do {
346 /* FIXME: Maybe delay __DRIdrawable creation until the drawable
347 * is actually bound to a context... */
348
349 __GLXdisplayPrivate * const priv = __glXInitialize(dpy);
350 __GLXDRIdrawable *pdraw;
351 __GLXscreenConfigs *psc;
352
353 psc = &priv->screenConfigs[fbconfig->screen];
354 if (psc->driScreen == NULL)
355 break;
356 pdraw = psc->driScreen->createDrawable(psc, drawable,
357 req->glxwindow, fbconfig);
358 if (pdraw == NULL) {
359 fprintf(stderr, "failed to create drawable\n");
360 break;
361 }
362
363 if (__glxHashInsert(psc->drawHash, req->glxwindow, pdraw)) {
364 (*pdraw->destroyDrawable)(pdraw);
365 return None; /* FIXME: Check what we're supposed to do here... */
366 }
367
368 pdraw->textureTarget = determineTextureTarget(attrib_list, i);
369 } while (0);
370 #endif
371
372 return (GLXDrawable)req->glxwindow;
373 }
374
375
376 /**
377 * Destroy a non-pbuffer GLX drawable.
378 *
379 * \todo
380 * This function needs to be modified to work with direct-rendering drivers.
381 */
382 static void
383 DestroyDrawable( Display * dpy, GLXDrawable drawable, CARD32 glxCode )
384 {
385 xGLXDestroyPbufferReq * req;
386 CARD8 opcode;
387
388 if ( (dpy == NULL) || (drawable == 0) ) {
389 return;
390 }
391
392
393 opcode = __glXSetupForCommand(dpy);
394 if (!opcode)
395 return;
396
397 LockDisplay(dpy);
398
399 GetReqExtra( GLXDestroyPbuffer, 4, req );
400 req->reqType = opcode;
401 req->glxCode = glxCode;
402 req->pbuffer = (GLXPbuffer) drawable;
403
404 UnlockDisplay(dpy);
405 SyncHandle();
406
407 #ifdef GLX_DIRECT_RENDERING
408 {
409 int screen;
410 __GLXdisplayPrivate * const priv = __glXInitialize(dpy);
411 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, &screen);
412 __GLXscreenConfigs *psc = &priv->screenConfigs[screen];
413
414 if (pdraw != NULL) {
415 (*pdraw->destroyDrawable)(pdraw);
416 __glxHashDelete(psc->drawHash, drawable);
417 }
418 }
419 #endif
420
421 return;
422 }
423
424
425 /**
426 * Create a pbuffer.
427 *
428 * This function is used to implement \c glXCreatePbuffer and
429 * \c glXCreateGLXPbufferSGIX.
430 *
431 * \note
432 * This function dynamically determines whether to use the SGIX_pbuffer
433 * version of the protocol or the GLX 1.3 version of the protocol.
434 *
435 * \todo
436 * This function needs to be modified to work with direct-rendering drivers.
437 */
438 static GLXDrawable
439 CreatePbuffer( Display *dpy, const __GLcontextModes * fbconfig,
440 unsigned int width, unsigned int height,
441 const int *attrib_list, GLboolean size_in_attribs )
442 {
443 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
444 GLXDrawable id = 0;
445 CARD32 * data;
446 CARD8 opcode;
447 unsigned int i;
448
449 i = 0;
450 if (attrib_list) {
451 while (attrib_list[i * 2])
452 i++;
453 }
454
455 opcode = __glXSetupForCommand(dpy);
456 if (!opcode)
457 return None;
458
459 LockDisplay(dpy);
460 id = XAllocID(dpy);
461
462 if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
463 xGLXCreatePbufferReq * req;
464 unsigned int extra = (size_in_attribs) ? 0 : 2;
465
466 GetReqExtra( GLXCreatePbuffer, (8 * (i + extra)), req );
467 data = (CARD32 *) (req + 1);
468
469 req->reqType = opcode;
470 req->glxCode = X_GLXCreatePbuffer;
471 req->screen = (CARD32) fbconfig->screen;
472 req->fbconfig = fbconfig->fbconfigID;
473 req->pbuffer = (GLXPbuffer) id;
474 req->numAttribs = (CARD32) (i + extra);
475
476 if ( ! size_in_attribs ) {
477 data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
478 data[(2 * i) + 1] = width;
479 data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
480 data[(2 * i) + 3] = height;
481 data += 4;
482 }
483 }
484 else {
485 xGLXVendorPrivateReq *vpreq;
486
487 GetReqExtra( GLXVendorPrivate, 20 + (8 * i), vpreq );
488 data = (CARD32 *) (vpreq + 1);
489
490 vpreq->reqType = opcode;
491 vpreq->glxCode = X_GLXVendorPrivate;
492 vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
493
494 data[0] = (CARD32) fbconfig->screen;
495 data[1] = (CARD32) fbconfig->fbconfigID;
496 data[2] = (CARD32) id;
497 data[3] = (CARD32) width;
498 data[4] = (CARD32) height;
499 data += 5;
500 }
501
502 (void) memcpy( data, attrib_list, sizeof(CARD32) * 2 * i );
503
504 UnlockDisplay(dpy);
505 SyncHandle();
506
507 return id;
508 }
509
510
511 /**
512 * Create a new pbuffer.
513 */
514 PUBLIC GLXPbufferSGIX
515 glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config,
516 unsigned int width, unsigned int height,
517 int *attrib_list)
518 {
519 return (GLXPbufferSGIX) CreatePbuffer( dpy, (__GLcontextModes *) config,
520 width, height,
521 attrib_list, GL_FALSE );
522 }
523
524
525 /**
526 * Create a new pbuffer.
527 */
528 PUBLIC GLXPbuffer
529 glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attrib_list)
530 {
531 int i, width, height;
532
533 width = 0;
534 height = 0;
535
536 for (i = 0; attrib_list[i * 2]; i++) {
537 switch (attrib_list[i * 2]) {
538 case GLX_PBUFFER_WIDTH:
539 width = attrib_list[i * 2 + 1];
540 break;
541 case GLX_PBUFFER_HEIGHT:
542 height = attrib_list[i * 2 + 1];
543 break;
544 }
545 }
546
547 return (GLXPbuffer) CreatePbuffer( dpy, (__GLcontextModes *) config,
548 width, height,
549 attrib_list, GL_TRUE );
550 }
551
552
553 /**
554 * Destroy an existing pbuffer.
555 */
556 PUBLIC void
557 glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
558 {
559 DestroyPbuffer( dpy, pbuf );
560 }
561
562
563 /**
564 * Query an attribute of a drawable.
565 */
566 PUBLIC void
567 glXQueryDrawable(Display *dpy, GLXDrawable drawable,
568 int attribute, unsigned int *value)
569 {
570 GetDrawableAttribute( dpy, drawable, attribute, value );
571 }
572
573
574 /**
575 * Query an attribute of a pbuffer.
576 */
577 PUBLIC int
578 glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX drawable,
579 int attribute, unsigned int *value)
580 {
581 return GetDrawableAttribute( dpy, drawable, attribute, value );
582 }
583
584
585 /**
586 * Select the event mask for a drawable.
587 */
588 PUBLIC void
589 glXSelectEvent(Display *dpy, GLXDrawable drawable, unsigned long mask)
590 {
591 CARD32 attribs[2];
592
593 attribs[0] = (CARD32) GLX_EVENT_MASK;
594 attribs[1] = (CARD32) mask;
595
596 ChangeDrawableAttribute( dpy, drawable, attribs, 1 );
597 }
598
599
600 /**
601 * Get the selected event mask for a drawable.
602 */
603 PUBLIC void
604 glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask)
605 {
606 unsigned int value;
607
608
609 /* The non-sense with value is required because on LP64 platforms
610 * sizeof(unsigned int) != sizeof(unsigned long). On little-endian
611 * we could just type-cast the pointer, but why?
612 */
613
614 GetDrawableAttribute( dpy, drawable, GLX_EVENT_MASK_SGIX, & value );
615 *mask = value;
616 }
617
618
619 PUBLIC GLXPixmap
620 glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap,
621 const int *attrib_list )
622 {
623 return CreateDrawable( dpy, (__GLcontextModes *) config,
624 (Drawable) pixmap, attrib_list,
625 X_GLXCreatePixmap );
626 }
627
628
629 PUBLIC GLXWindow
630 glXCreateWindow( Display *dpy, GLXFBConfig config, Window win,
631 const int *attrib_list )
632 {
633 return CreateDrawable( dpy, (__GLcontextModes *) config,
634 (Drawable) win, attrib_list,
635 X_GLXCreateWindow );
636 }
637
638
639 PUBLIC void
640 glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
641 {
642 DestroyDrawable( dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap );
643 }
644
645
646 PUBLIC void
647 glXDestroyWindow(Display *dpy, GLXWindow win)
648 {
649 DestroyDrawable( dpy, (GLXDrawable) win, X_GLXDestroyWindow );
650 }
651
652
653 PUBLIC GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
654 (Display *dpy, GLXPbufferSGIX pbuf),
655 (dpy, pbuf),
656 glXDestroyPbuffer)
657
658 PUBLIC GLX_ALIAS_VOID(glXSelectEventSGIX,
659 (Display *dpy, GLXDrawable drawable, unsigned long mask),
660 (dpy, drawable, mask),
661 glXSelectEvent)
662
663 PUBLIC GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
664 (Display *dpy, GLXDrawable drawable, unsigned long *mask),
665 (dpy, drawable, mask),
666 glXGetSelectedEvent)