Coverity #943: Avoid a NULL chase.
[profile/ivi/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
76
77    if ( (dpy == NULL) || (drawable == 0) ) {
78       return;
79    }
80
81
82    LockDisplay(dpy);
83
84    if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
85       xGLXChangeDrawableAttributesReq *req;
86
87       GetReqExtra( GLXChangeDrawableAttributes, 8 + (8 * num_attribs), req );
88       output = (CARD32 *) (req + 1);
89
90       req->reqType = __glXSetupForCommand(dpy);
91       req->glxCode = X_GLXChangeDrawableAttributes;
92       req->drawable = drawable;
93       req->numAttribs = (CARD32) num_attribs;
94    }
95    else {
96       xGLXVendorPrivateWithReplyReq *vpreq;
97
98       GetReqExtra( GLXVendorPrivateWithReply, 4 + (8 * num_attribs), vpreq );
99       output = (CARD32 *) (vpreq + 1);
100
101       vpreq->reqType = __glXSetupForCommand(dpy);
102       vpreq->glxCode = X_GLXVendorPrivateWithReply;
103       vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX;
104
105       output[0] = (CARD32) drawable;
106       output++;
107    }
108
109    (void) memcpy( output, attribs, sizeof( CARD32 ) * 2 * num_attribs );
110
111    UnlockDisplay(dpy);
112    SyncHandle();
113
114    return;
115 }
116
117
118 /**
119  * Destroy a pbuffer.
120  *
121  * This function is used to implement \c glXDestroyPbuffer and
122  * \c glXDestroyGLXPbufferSGIX.
123  *
124  * \note
125  * This function dynamically determines whether to use the SGIX_pbuffer
126  * version of the protocol or the GLX 1.3 version of the protocol.
127  * 
128  * \todo
129  * This function needs to be modified to work with direct-rendering drivers.
130  */
131 static void
132 DestroyPbuffer( Display * dpy, GLXDrawable drawable )
133 {
134    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
135
136    if ( (dpy == NULL) || (drawable == 0) ) {
137       return;
138    }
139
140
141    LockDisplay(dpy);
142
143    if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
144       xGLXDestroyPbufferReq * req;
145
146       GetReqExtra( GLXDestroyPbuffer, 4, req );
147       req->reqType = __glXSetupForCommand(dpy);
148       req->glxCode = X_GLXDestroyPbuffer;
149       req->pbuffer = (GLXPbuffer) drawable;
150    }
151    else {
152       xGLXVendorPrivateWithReplyReq *vpreq;
153       CARD32 * data;
154
155       GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
156       data = (CARD32 *) (vpreq + 1);
157
158       data[0] = (CARD32) drawable;
159
160       vpreq->reqType = __glXSetupForCommand(dpy);
161       vpreq->glxCode = X_GLXVendorPrivateWithReply;
162       vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
163    }
164
165    UnlockDisplay(dpy);
166    SyncHandle();
167
168    return;
169 }
170
171
172 /**
173  * Get a drawable's attribute.
174  *
175  * This function is used to implement \c glXGetSelectedEvent and
176  * \c glXGetSelectedEventSGIX.
177  *
178  * \note
179  * This function dynamically determines whether to use the SGIX_pbuffer
180  * version of the protocol or the GLX 1.3 version of the protocol.
181  *
182  * \todo
183  * The number of attributes returned is likely to be small, probably less than
184  * 10.  Given that, this routine should try to use an array on the stack to
185  * capture the reply rather than always calling Xmalloc.
186  *
187  * \todo
188  * This function needs to be modified to work with direct-rendering drivers.
189  */
190 static int
191 GetDrawableAttribute( Display *dpy, GLXDrawable drawable,
192                       int attribute, unsigned int *value )
193 {
194    __GLXdisplayPrivate *priv;
195    xGLXGetDrawableAttributesReply reply;
196    CARD32 * data;
197    unsigned int length;
198    unsigned int i;
199    unsigned int num_attributes;
200
201    if ( (dpy == NULL) || (drawable == 0) ) {
202       return 0;
203    }
204
205    priv = __glXInitialize(dpy);
206    GLboolean use_glx_1_3 = ((priv->majorVersion > 1)
207                             || (priv->minorVersion >= 3));
208
209    *value = 0;
210
211
212    
213    LockDisplay(dpy);
214
215    if ( use_glx_1_3 ) {
216       xGLXGetDrawableAttributesReq *req;
217
218       GetReqExtra( GLXGetDrawableAttributes, 4, req );
219       req->reqType = __glXSetupForCommand(dpy);
220       req->glxCode = X_GLXGetDrawableAttributes;
221       req->drawable = drawable;
222    }
223    else {
224       xGLXVendorPrivateWithReplyReq *vpreq;
225
226       GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
227       data = (CARD32 *) (vpreq + 1);
228       data[0] = (CARD32) drawable;
229
230       vpreq->reqType = __glXSetupForCommand(dpy);
231       vpreq->glxCode = X_GLXVendorPrivateWithReply;
232       vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
233    }
234
235    _XReply(dpy, (xReply*) &reply, 0, False);
236
237    if (reply.type == X_Error)
238    {
239        UnlockDisplay(dpy);
240        SyncHandle();
241        return 0;
242    }
243
244    length = reply.length;
245    if (length)
246    {
247        num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
248        data = (CARD32 *) Xmalloc( length * sizeof(CARD32) );
249        if ( data == NULL ) {
250            /* Throw data on the floor */
251            _XEatData(dpy, length);
252        } else {
253            _XRead(dpy, (char *)data, length * sizeof(CARD32) );
254
255            /* Search the set of returned attributes for the attribute requested by
256             * the caller.
257             */
258            for ( i = 0 ; i < num_attributes ; i++ ) {
259                if ( data[i*2] == attribute ) {
260                    *value = data[ (i*2) + 1 ];
261                    break;
262                }
263            }
264
265            Xfree( data );
266        }
267    }
268
269    UnlockDisplay(dpy);
270    SyncHandle();
271
272    return 0;
273 }
274
275
276 /**
277  * Create a non-pbuffer GLX drawable.
278  *
279  * \todo
280  * This function needs to be modified to work with direct-rendering drivers.
281  */
282 static GLXDrawable
283 CreateDrawable( Display *dpy, const __GLcontextModes * fbconfig,
284                 Drawable drawable, const int *attrib_list,
285                 CARD8 glxCode )
286 {
287    xGLXCreateWindowReq * req;
288    CARD32 * data;
289    unsigned int i;
290
291    i = 0;
292    if (attrib_list) {
293        while (attrib_list[i * 2] != None)
294            i++;
295    }
296
297    LockDisplay(dpy);
298    GetReqExtra( GLXCreateWindow, 8 * i, req );
299    data = (CARD32 *) (req + 1);
300
301    req->reqType = __glXSetupForCommand(dpy);
302    req->glxCode = glxCode;
303    req->screen = (CARD32) fbconfig->screen;
304    req->fbconfig = fbconfig->fbconfigID;
305    req->window = (GLXPbuffer) drawable;
306    req->glxwindow = (GLXWindow) XAllocID(dpy);
307    req->numAttribs = (CARD32) i;
308
309    memcpy( data, attrib_list, 8 * i );
310    
311    UnlockDisplay(dpy);
312    SyncHandle();
313    
314    return (GLXDrawable)req->glxwindow;
315 }
316
317
318 /**
319  * Destroy a non-pbuffer GLX drawable.
320  *
321  * \todo
322  * This function needs to be modified to work with direct-rendering drivers.
323  */
324 static void
325 DestroyDrawable( Display * dpy, GLXDrawable drawable, CARD32 glxCode )
326 {
327    xGLXDestroyPbufferReq * req;
328
329    if ( (dpy == NULL) || (drawable == 0) ) {
330       return;
331    }
332
333
334    LockDisplay(dpy);
335
336    GetReqExtra( GLXDestroyPbuffer, 4, req );
337    req->reqType = __glXSetupForCommand(dpy);
338    req->glxCode = glxCode;
339    req->pbuffer = (GLXPbuffer) drawable;
340
341    UnlockDisplay(dpy);
342    SyncHandle();
343
344    return;
345 }
346
347
348 /**
349  * Create a pbuffer.
350  *
351  * This function is used to implement \c glXCreatePbuffer and
352  * \c glXCreateGLXPbufferSGIX.
353  *
354  * \note
355  * This function dynamically determines whether to use the SGIX_pbuffer
356  * version of the protocol or the GLX 1.3 version of the protocol.
357  *
358  * \todo
359  * This function needs to be modified to work with direct-rendering drivers.
360  */
361 static GLXDrawable
362 CreatePbuffer( Display *dpy, const __GLcontextModes * fbconfig,
363                unsigned int width, unsigned int height, 
364                const int *attrib_list, GLboolean size_in_attribs )
365 {
366    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
367    GLXDrawable id = 0;
368    CARD32 * data;
369    unsigned int  i;
370
371    i = 0;
372    if (attrib_list) {
373        while (attrib_list[i * 2])
374            i++;
375    }
376
377    LockDisplay(dpy);
378    id = XAllocID(dpy);
379
380    if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
381       xGLXCreatePbufferReq * req;
382       unsigned int extra = (size_in_attribs) ? 0 : 2;
383
384       GetReqExtra( GLXCreatePbuffer, (8 * (i + extra)), req );
385       data = (CARD32 *) (req + 1);
386
387       req->reqType = __glXSetupForCommand(dpy);
388       req->glxCode = X_GLXCreatePbuffer;
389       req->screen = (CARD32) fbconfig->screen;
390       req->fbconfig = fbconfig->fbconfigID;
391       req->pbuffer = (GLXPbuffer) id;
392       req->numAttribs = (CARD32) (i + extra);
393
394       if ( ! size_in_attribs ) {
395          data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
396          data[(2 * i) + 1] = width;
397          data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
398          data[(2 * i) + 3] = height;
399          data += 4;
400       }
401    }
402    else {
403       xGLXVendorPrivateReq *vpreq;
404
405       GetReqExtra( GLXVendorPrivate, 20 + (8 * i), vpreq );
406       data = (CARD32 *) (vpreq + 1);
407
408       vpreq->reqType = __glXSetupForCommand(dpy);
409       vpreq->glxCode = X_GLXVendorPrivate;
410       vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
411
412       data[0] = (CARD32) fbconfig->screen;
413       data[1] = (CARD32) fbconfig->fbconfigID;
414       data[2] = (CARD32) id;
415       data[3] = (CARD32) width;
416       data[4] = (CARD32) height;
417       data += 5;
418    }
419
420    (void) memcpy( data, attrib_list, sizeof(CARD32) * 2 * i );
421
422    UnlockDisplay(dpy);
423    SyncHandle();
424
425    return id;
426 }
427
428
429 /**
430  * Create a new pbuffer.
431  */
432 PUBLIC GLXPbufferSGIX
433 glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config,
434                         unsigned int width, unsigned int height,
435                         int *attrib_list)
436 {
437    return (GLXPbufferSGIX) CreatePbuffer( dpy, (__GLcontextModes *) config,
438                                           width, height,
439                                           attrib_list, GL_FALSE );
440 }
441
442
443 /**
444  * Create a new pbuffer.
445  */
446 PUBLIC GLXPbuffer
447 glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attrib_list)
448 {
449    return (GLXPbuffer) CreatePbuffer( dpy, (__GLcontextModes *) config,
450                                       0, 0,
451                                       attrib_list, GL_TRUE );
452 }
453
454
455 /**
456  * Destroy an existing pbuffer.
457  */
458 PUBLIC void
459 glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
460 {
461    DestroyPbuffer( dpy, pbuf );
462 }
463
464
465 /**
466  * Query an attribute of a drawable.
467  */
468 PUBLIC void
469 glXQueryDrawable(Display *dpy, GLXDrawable drawable,
470                  int attribute, unsigned int *value)
471 {
472    GetDrawableAttribute( dpy, drawable, attribute, value );
473 }
474
475
476 /**
477  * Query an attribute of a pbuffer.
478  */
479 PUBLIC int
480 glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX drawable,
481                        int attribute, unsigned int *value)
482 {
483    return GetDrawableAttribute( dpy, drawable, attribute, value );
484 }
485
486
487 /**
488  * Select the event mask for a drawable.
489  */
490 PUBLIC void
491 glXSelectEvent(Display *dpy, GLXDrawable drawable, unsigned long mask)
492 {
493    CARD32 attribs[2];
494
495    attribs[0] = (CARD32) GLX_EVENT_MASK;
496    attribs[1] = (CARD32) mask;
497
498    ChangeDrawableAttribute( dpy, drawable, attribs, 1 );
499 }
500
501
502 /**
503  * Get the selected event mask for a drawable.
504  */
505 PUBLIC void
506 glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask)
507 {
508    unsigned int value;
509
510
511    /* The non-sense with value is required because on LP64 platforms
512     * sizeof(unsigned int) != sizeof(unsigned long).  On little-endian
513     * we could just type-cast the pointer, but why?
514     */
515
516    GetDrawableAttribute( dpy, drawable, GLX_EVENT_MASK_SGIX, & value );
517    *mask = value;
518 }
519
520
521 PUBLIC GLXPixmap
522 glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap,
523                  const int *attrib_list )
524 {
525    return CreateDrawable( dpy, (__GLcontextModes *) config,
526                           (Drawable) pixmap, attrib_list,
527                           X_GLXCreatePixmap );
528 }
529
530
531 PUBLIC GLXWindow
532 glXCreateWindow( Display *dpy, GLXFBConfig config, Window win,
533                  const int *attrib_list )
534 {
535    return CreateDrawable( dpy, (__GLcontextModes *) config,
536                           (Drawable) win, attrib_list,
537                           X_GLXCreateWindow );
538 }
539
540
541 PUBLIC void
542 glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
543 {
544    DestroyDrawable( dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap );
545 }
546
547
548 PUBLIC void
549 glXDestroyWindow(Display *dpy, GLXWindow win)
550 {
551    DestroyDrawable( dpy, (GLXDrawable) win, X_GLXDestroyWindow );
552 }
553
554
555 PUBLIC GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
556           (Display *dpy, GLXPbufferSGIX pbuf),
557           (dpy, pbuf),
558           glXDestroyPbuffer)
559
560 PUBLIC GLX_ALIAS_VOID(glXSelectEventSGIX,
561           (Display *dpy, GLXDrawable drawable, unsigned long mask),
562           (dpy, drawable, mask),
563           glXSelectEvent)
564
565 PUBLIC GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
566           (Display *dpy, GLXDrawable drawable, unsigned long *mask),
567           (dpy, drawable, mask),
568           glXGetSelectedEvent)