2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Framebuffer and renderbuffer-related functions.
32 #include "glxheader.h"
34 #include "main/imports.h"
35 #include "main/formats.h"
36 #include "main/framebuffer.h"
37 #include "main/renderbuffer.h"
40 #if defined(USE_XSHM) && !defined(XFree86Server)
41 static volatile int mesaXErrorFlag
= 0;
44 * Catches potential Xlib errors.
47 mesaHandleXError(XMesaDisplay
*dpy
, XErrorEvent
*event
)
56 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
57 * Return: GL_TRUE if success, GL_FALSE if error
60 alloc_back_shm_ximage(XMesaBuffer b
, GLuint width
, GLuint height
)
63 * We have to do a _lot_ of error checking here to be sure we can
64 * really use the XSHM extension. It seems different servers trigger
65 * errors at different points if the extension won't work. Therefore
66 * we have to be very careful...
69 int (*old_handler
)(XMesaDisplay
*, XErrorEvent
*);
71 if (width
== 0 || height
== 0) {
72 /* this will be true the first time we're called on 'b' */
76 b
->backxrb
->ximage
= XShmCreateImage(b
->xm_visual
->display
,
77 b
->xm_visual
->visinfo
->visual
,
78 b
->xm_visual
->visinfo
->depth
,
79 ZPixmap
, NULL
, &b
->shminfo
,
81 if (b
->backxrb
->ximage
== NULL
) {
82 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (XShmCreateImage), disabling.\n");
87 b
->shminfo
.shmid
= shmget(IPC_PRIVATE
, b
->backxrb
->ximage
->bytes_per_line
88 * b
->backxrb
->ximage
->height
, IPC_CREAT
|0777);
89 if (b
->shminfo
.shmid
< 0) {
90 _mesa_warning(NULL
, "shmget failed while allocating back buffer.\n");
91 XDestroyImage(b
->backxrb
->ximage
);
92 b
->backxrb
->ximage
= NULL
;
93 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (shmget), disabling.\n");
98 b
->shminfo
.shmaddr
= b
->backxrb
->ximage
->data
99 = (char*)shmat(b
->shminfo
.shmid
, 0, 0);
100 if (b
->shminfo
.shmaddr
== (char *) -1) {
101 _mesa_warning(NULL
, "shmat() failed while allocating back buffer.\n");
102 XDestroyImage(b
->backxrb
->ximage
);
103 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
104 b
->backxrb
->ximage
= NULL
;
105 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (shmat), disabling.\n");
110 b
->shminfo
.readOnly
= False
;
112 old_handler
= XSetErrorHandler(mesaHandleXError
);
113 /* This may trigger the X protocol error we're ready to catch: */
114 XShmAttach(b
->xm_visual
->display
, &b
->shminfo
);
115 XSync(b
->xm_visual
->display
, False
);
117 if (mesaXErrorFlag
) {
118 /* we are on a remote display, this error is normal, don't print it */
119 XFlush(b
->xm_visual
->display
);
121 XDestroyImage(b
->backxrb
->ximage
);
122 shmdt(b
->shminfo
.shmaddr
);
123 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
124 b
->backxrb
->ximage
= NULL
;
126 (void) XSetErrorHandler(old_handler
);
130 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0); /* nobody else needs it */
132 /* Finally, try an XShmPutImage to be really sure the extension works */
133 gc
= XCreateGC(b
->xm_visual
->display
, b
->frontxrb
->drawable
, 0, NULL
);
134 XShmPutImage(b
->xm_visual
->display
, b
->frontxrb
->drawable
, gc
,
135 b
->backxrb
->ximage
, 0, 0, 0, 0, 1, 1 /*one pixel*/, False
);
136 XSync(b
->xm_visual
->display
, False
);
137 XFreeGC(b
->xm_visual
->display
, gc
);
138 (void) XSetErrorHandler(old_handler
);
139 if (mesaXErrorFlag
) {
140 XFlush(b
->xm_visual
->display
);
142 XDestroyImage(b
->backxrb
->ximage
);
143 shmdt(b
->shminfo
.shmaddr
);
144 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
145 b
->backxrb
->ximage
= NULL
;
154 alloc_back_shm_ximage(XMesaBuffer b
, GLuint width
, GLuint height
)
156 /* Can't compile XSHM support */
164 * Setup an off-screen pixmap or Ximage to use as the back buffer.
165 * Input: b - the X/Mesa buffer
168 alloc_back_buffer(XMesaBuffer b
, GLuint width
, GLuint height
)
170 if (b
->db_mode
== BACK_XIMAGE
) {
171 /* Deallocate the old backxrb->ximage, if any */
172 if (b
->backxrb
->ximage
) {
173 #if defined(USE_XSHM) && !defined(XFree86Server)
175 XShmDetach(b
->xm_visual
->display
, &b
->shminfo
);
176 XDestroyImage(b
->backxrb
->ximage
);
177 shmdt(b
->shminfo
.shmaddr
);
181 XMesaDestroyImage(b
->backxrb
->ximage
);
182 b
->backxrb
->ximage
= NULL
;
185 if (width
== 0 || height
== 0)
188 /* Allocate new back buffer */
189 if (b
->shm
== 0 || !alloc_back_shm_ximage(b
, width
, height
)) {
190 /* Allocate a regular XImage for the back buffer. */
192 b
->backxrb
->ximage
= XMesaCreateImage(b
->xm_visual
->BitsPerPixel
,
193 width
, height
, NULL
);
195 b
->backxrb
->ximage
= XCreateImage(b
->xm_visual
->display
,
196 b
->xm_visual
->visinfo
->visual
,
197 GET_VISUAL_DEPTH(b
->xm_visual
),
198 ZPixmap
, 0, /* format, offset */
201 8, 0); /* pad, bytes_per_line */
203 if (!b
->backxrb
->ximage
) {
204 _mesa_warning(NULL
, "alloc_back_buffer: XCreateImage failed.\n");
207 b
->backxrb
->ximage
->data
= (char *) MALLOC(b
->backxrb
->ximage
->height
208 * b
->backxrb
->ximage
->bytes_per_line
);
209 if (!b
->backxrb
->ximage
->data
) {
210 _mesa_warning(NULL
, "alloc_back_buffer: MALLOC failed.\n");
211 XMesaDestroyImage(b
->backxrb
->ximage
);
212 b
->backxrb
->ximage
= NULL
;
215 b
->backxrb
->pixmap
= None
;
217 else if (b
->db_mode
== BACK_PIXMAP
) {
218 /* Free the old back pixmap */
219 if (b
->backxrb
->pixmap
) {
220 XMesaFreePixmap(b
->xm_visual
->display
, b
->backxrb
->pixmap
);
221 b
->backxrb
->pixmap
= 0;
224 if (width
> 0 && height
> 0) {
225 /* Allocate new back pixmap */
226 b
->backxrb
->pixmap
= XMesaCreatePixmap(b
->xm_visual
->display
,
227 b
->frontxrb
->drawable
,
229 GET_VISUAL_DEPTH(b
->xm_visual
));
232 b
->backxrb
->ximage
= NULL
;
233 b
->backxrb
->drawable
= b
->backxrb
->pixmap
;
239 xmesa_delete_renderbuffer(struct gl_renderbuffer
*rb
)
241 /* XXX Note: the ximage or Pixmap attached to this renderbuffer
242 * should probably get freed here, but that's currently done in
243 * XMesaDestroyBuffer().
250 * Reallocate renderbuffer storage for front color buffer.
251 * Called via gl_renderbuffer::AllocStorage()
254 xmesa_alloc_front_storage(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
255 GLenum internalFormat
, GLuint width
, GLuint height
)
257 struct xmesa_renderbuffer
*xrb
= xmesa_renderbuffer(rb
);
259 /* just clear these to be sure we don't accidentally use them */
265 /* for the FLIP macro: */
266 xrb
->bottom
= height
- 1;
270 rb
->InternalFormat
= internalFormat
;
277 * Reallocate renderbuffer storage for back color buffer.
278 * Called via gl_renderbuffer::AllocStorage()
281 xmesa_alloc_back_storage(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
282 GLenum internalFormat
, GLuint width
, GLuint height
)
284 struct xmesa_renderbuffer
*xrb
= xmesa_renderbuffer(rb
);
286 /* reallocate the back buffer XImage or Pixmap */
288 alloc_back_buffer(xrb
->Parent
, width
, height
);
290 /* same as front buffer */
291 /* XXX why is this here? */
292 (void) xmesa_alloc_front_storage(ctx
, rb
, internalFormat
, width
, height
);
296 /* Needed by PIXELADDR1 macro */
297 xrb
->width1
= xrb
->ximage
->bytes_per_line
;
298 xrb
->origin1
= (GLubyte
*) xrb
->ximage
->data
+ xrb
->width1
* (height
- 1);
300 /* Needed by PIXELADDR2 macro */
301 xrb
->width2
= xrb
->ximage
->bytes_per_line
/ 2;
302 xrb
->origin2
= (GLushort
*) xrb
->ximage
->data
+ xrb
->width2
* (height
- 1);
304 /* Needed by PIXELADDR3 macro */
305 xrb
->width3
= xrb
->ximage
->bytes_per_line
;
306 xrb
->origin3
= (GLubyte
*) xrb
->ximage
->data
+ xrb
->width3
* (height
- 1);
308 /* Needed by PIXELADDR4 macro */
309 xrb
->width4
= xrb
->ximage
->width
;
310 xrb
->origin4
= (GLuint
*) xrb
->ximage
->data
+ xrb
->width4
* (height
- 1);
313 /* out of memory or buffer size is 0 x 0 */
314 xrb
->width1
= xrb
->width2
= xrb
->width3
= xrb
->width4
= 0;
325 struct xmesa_renderbuffer
*
326 xmesa_new_renderbuffer(struct gl_context
*ctx
, GLuint name
, const struct gl_config
*visual
,
327 GLboolean backBuffer
)
329 struct xmesa_renderbuffer
*xrb
= CALLOC_STRUCT(xmesa_renderbuffer
);
332 _mesa_init_renderbuffer(&xrb
->Base
, name
);
334 xrb
->Base
.Delete
= xmesa_delete_renderbuffer
;
336 xrb
->Base
.AllocStorage
= xmesa_alloc_back_storage
;
338 xrb
->Base
.AllocStorage
= xmesa_alloc_front_storage
;
340 xrb
->Base
.InternalFormat
= GL_RGBA
;
341 xrb
->Base
.Format
= MESA_FORMAT_RGBA8888
;
342 xrb
->Base
._BaseFormat
= GL_RGBA
;
343 xrb
->Base
.DataType
= GL_UNSIGNED_BYTE
;
344 /* only need to set Red/Green/EtcBits fields for user-created RBs */
351 * Called via gl_framebuffer::Delete() method when this buffer
352 * is _really_ being deleted.
355 xmesa_delete_framebuffer(struct gl_framebuffer
*fb
)
357 XMesaBuffer b
= XMESA_BUFFER(fb
);
359 if (b
->num_alloced
> 0) {
360 /* If no other buffer uses this X colormap then free the colors. */
361 if (!xmesa_find_buffer(b
->display
, b
->cmap
, b
)) {
364 if (b
->frontxrb
->drawable
)
365 client
= CLIENT_ID(b
->frontxrb
->drawable
->id
);
366 (void)FreeColors(b
->cmap
, client
,
367 b
->num_alloced
, b
->alloced_colors
, 0);
369 XFreeColors(b
->display
, b
->cmap
,
370 b
->alloced_colors
, b
->num_alloced
, 0);
376 XMesaFreeGC(b
->display
, b
->gc
);
378 XMesaFreeGC(b
->display
, b
->cleargc
);
380 XMesaFreeGC(b
->display
, b
->swapgc
);
382 if (fb
->Visual
.doubleBufferMode
) {
383 /* free back ximage/pixmap/shmregion */
384 if (b
->backxrb
->ximage
) {
385 #if defined(USE_XSHM) && !defined(XFree86Server)
387 XShmDetach( b
->display
, &b
->shminfo
);
388 XDestroyImage( b
->backxrb
->ximage
);
389 shmdt( b
->shminfo
.shmaddr
);
393 XMesaDestroyImage( b
->backxrb
->ximage
);
394 b
->backxrb
->ximage
= NULL
;
396 if (b
->backxrb
->pixmap
) {
397 XMesaFreePixmap( b
->display
, b
->backxrb
->pixmap
);
398 if (b
->xm_visual
->hpcr_clear_flag
) {
399 XMesaFreePixmap( b
->display
,
400 b
->xm_visual
->hpcr_clear_pixmap
);
401 XMesaDestroyImage( b
->xm_visual
->hpcr_clear_ximage
);
407 free( b
->rowimage
->data
);
408 b
->rowimage
->data
= NULL
;
409 XMesaDestroyImage( b
->rowimage
);
412 _mesa_free_framebuffer_data(fb
);