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