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"
36 #include "framebuffer.h"
37 #include "renderbuffer.h"
38 #include "pipe/p_state.h"
39 #include "pipe/p_defines.h"
40 #include "pipe/p_winsys.h"
41 #include "state_tracker/st_context.h"
44 #if defined(USE_XSHM) && !defined(XFree86Server)
45 static volatile int mesaXErrorFlag
= 0;
48 * Catches potential Xlib errors.
51 mesaHandleXError(XMesaDisplay
*dpy
, XErrorEvent
*event
)
60 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
61 * Return: GL_TRUE if success, GL_FALSE if error
64 alloc_back_shm_ximage(XMesaBuffer b
, GLuint width
, GLuint height
)
67 * We have to do a _lot_ of error checking here to be sure we can
68 * really use the XSHM extension. It seems different servers trigger
69 * errors at different points if the extension won't work. Therefore
70 * we have to be very careful...
73 int (*old_handler
)(XMesaDisplay
*, XErrorEvent
*);
75 if (width
== 0 || height
== 0) {
76 /* this will be true the first time we're called on 'b' */
80 b
->backxrb
->ximage
= XShmCreateImage(b
->xm_visual
->display
,
81 b
->xm_visual
->visinfo
->visual
,
82 b
->xm_visual
->visinfo
->depth
,
83 ZPixmap
, NULL
, &b
->shminfo
,
85 if (b
->backxrb
->ximage
== NULL
) {
86 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (XShmCreateImage), disabling.\n");
91 b
->shminfo
.shmid
= shmget(IPC_PRIVATE
, b
->backxrb
->ximage
->bytes_per_line
92 * b
->backxrb
->ximage
->height
, IPC_CREAT
|0777);
93 if (b
->shminfo
.shmid
< 0) {
94 _mesa_warning(NULL
, "shmget failed while allocating back buffer.\n");
95 XDestroyImage(b
->backxrb
->ximage
);
96 b
->backxrb
->ximage
= NULL
;
97 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (shmget), disabling.\n");
102 b
->shminfo
.shmaddr
= b
->backxrb
->ximage
->data
103 = (char*)shmat(b
->shminfo
.shmid
, 0, 0);
104 if (b
->shminfo
.shmaddr
== (char *) -1) {
105 _mesa_warning(NULL
, "shmat() failed while allocating back buffer.\n");
106 XDestroyImage(b
->backxrb
->ximage
);
107 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
108 b
->backxrb
->ximage
= NULL
;
109 _mesa_warning(NULL
, "alloc_back_buffer: Shared memory error (shmat), disabling.\n");
114 b
->shminfo
.readOnly
= False
;
116 old_handler
= XSetErrorHandler(mesaHandleXError
);
117 /* This may trigger the X protocol error we're ready to catch: */
118 XShmAttach(b
->xm_visual
->display
, &b
->shminfo
);
119 XSync(b
->xm_visual
->display
, False
);
121 if (mesaXErrorFlag
) {
122 /* we are on a remote display, this error is normal, don't print it */
123 XFlush(b
->xm_visual
->display
);
125 XDestroyImage(b
->backxrb
->ximage
);
126 shmdt(b
->shminfo
.shmaddr
);
127 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
128 b
->backxrb
->ximage
= NULL
;
130 (void) XSetErrorHandler(old_handler
);
134 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0); /* nobody else needs it */
136 /* Finally, try an XShmPutImage to be really sure the extension works */
137 gc
= XCreateGC(b
->xm_visual
->display
, b
->frontxrb
->drawable
, 0, NULL
);
138 XShmPutImage(b
->xm_visual
->display
, b
->frontxrb
->drawable
, gc
,
139 b
->backxrb
->ximage
, 0, 0, 0, 0, 1, 1 /*one pixel*/, False
);
140 XSync(b
->xm_visual
->display
, False
);
141 XFreeGC(b
->xm_visual
->display
, gc
);
142 (void) XSetErrorHandler(old_handler
);
143 if (mesaXErrorFlag
) {
144 XFlush(b
->xm_visual
->display
);
146 XDestroyImage(b
->backxrb
->ximage
);
147 shmdt(b
->shminfo
.shmaddr
);
148 shmctl(b
->shminfo
.shmid
, IPC_RMID
, 0);
149 b
->backxrb
->ximage
= NULL
;
158 alloc_back_shm_ximage(XMesaBuffer b
, GLuint width
, GLuint height
)
160 /* Can't compile XSHM support */
168 * Setup an off-screen pixmap or Ximage to use as the back buffer.
169 * Input: b - the X/Mesa buffer
172 alloc_back_buffer(XMesaBuffer b
, GLuint width
, GLuint height
)
174 if (b
->db_mode
== BACK_XIMAGE
) {
175 /* Deallocate the old backxrb->ximage, if any */
176 if (b
->backxrb
->ximage
) {
177 #if defined(USE_XSHM) && !defined(XFree86Server)
179 XShmDetach(b
->xm_visual
->display
, &b
->shminfo
);
180 XDestroyImage(b
->backxrb
->ximage
);
181 shmdt(b
->shminfo
.shmaddr
);
185 XMesaDestroyImage(b
->backxrb
->ximage
);
186 b
->backxrb
->ximage
= NULL
;
189 if (width
== 0 || height
== 0)
192 /* Allocate new back buffer */
193 if (b
->shm
== 0 || !alloc_back_shm_ximage(b
, width
, height
)) {
194 /* Allocate a regular XImage for the back buffer. */
196 b
->backxrb
->ximage
= XMesaCreateImage(b
->xm_visual
->BitsPerPixel
,
197 width
, height
, NULL
);
199 b
->backxrb
->ximage
= XCreateImage(b
->xm_visual
->display
,
200 b
->xm_visual
->visinfo
->visual
,
201 GET_VISUAL_DEPTH(b
->xm_visual
),
202 ZPixmap
, 0, /* format, offset */
205 8, 0); /* pad, bytes_per_line */
207 if (!b
->backxrb
->ximage
) {
208 _mesa_warning(NULL
, "alloc_back_buffer: XCreateImage failed.\n");
211 b
->backxrb
->ximage
->data
= (char *) MALLOC(b
->backxrb
->ximage
->height
212 * b
->backxrb
->ximage
->bytes_per_line
);
213 if (!b
->backxrb
->ximage
->data
) {
214 _mesa_warning(NULL
, "alloc_back_buffer: MALLOC failed.\n");
215 XMesaDestroyImage(b
->backxrb
->ximage
);
216 b
->backxrb
->ximage
= NULL
;
219 b
->backxrb
->pixmap
= None
;
221 else if (b
->db_mode
== BACK_PIXMAP
) {
222 /* Free the old back pixmap */
223 if (b
->backxrb
->pixmap
) {
224 XMesaFreePixmap(b
->xm_visual
->display
, b
->backxrb
->pixmap
);
225 b
->backxrb
->pixmap
= 0;
228 if (width
> 0 && height
> 0) {
229 /* Allocate new back pixmap */
230 b
->backxrb
->pixmap
= XMesaCreatePixmap(b
->xm_visual
->display
,
231 b
->frontxrb
->drawable
,
233 GET_VISUAL_DEPTH(b
->xm_visual
));
236 b
->backxrb
->ximage
= NULL
;
242 xmesa_delete_renderbuffer(struct gl_renderbuffer
*rb
)
244 /* XXX Note: the ximage or Pixmap attached to this renderbuffer
245 * should probably get freed here, but that's currently done in
246 * XMesaDestroyBuffer().
253 finish_surface_init(GLcontext
*ctx
, struct xmesa_renderbuffer
*xrb
)
255 struct pipe_context
*pipe
= ctx
->st
->pipe
;
256 if (!xrb
->St
.surface
->region
) {
258 xrb
->St
.surface
->region
= pipe
->winsys
->region_alloc(pipe
->winsys
,
265 * Reallocate renderbuffer storage for front color buffer.
266 * Called via gl_renderbuffer::AllocStorage()
269 xmesa_alloc_front_storage(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
270 GLenum internalFormat
, GLuint width
, GLuint height
)
272 struct xmesa_renderbuffer
*xrb
= xmesa_renderbuffer(rb
);
274 /* just clear these to be sure we don't accidentally use them */
280 /* for the FLIP macro: */
281 xrb
->bottom
= height
- 1;
285 rb
->InternalFormat
= internalFormat
;
287 if (!xrb
->St
.surface
|| !xrb
->St
.surface
->region
)
288 finish_surface_init(ctx
, xrb
);
290 xrb
->St
.surface
->width
= width
;
291 xrb
->St
.surface
->height
= height
;
298 * Reallocate renderbuffer storage for back color buffer.
299 * Called via gl_renderbuffer::AllocStorage()
302 xmesa_alloc_back_storage(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
303 GLenum internalFormat
, GLuint width
, GLuint height
)
305 struct xmesa_renderbuffer
*xrb
= xmesa_renderbuffer(rb
);
307 /* reallocate the back buffer XImage or Pixmap */
309 alloc_back_buffer(xrb
->Parent
, width
, height
);
311 /* same as front buffer */
312 /* XXX why is this here? */
313 (void) xmesa_alloc_front_storage(ctx
, rb
, internalFormat
, width
, height
);
317 /* Needed by PIXELADDR1 macro */
318 xrb
->width1
= xrb
->ximage
->bytes_per_line
;
319 xrb
->origin1
= (GLubyte
*) xrb
->ximage
->data
+ xrb
->width1
* (height
- 1);
321 /* Needed by PIXELADDR2 macro */
322 xrb
->width2
= xrb
->ximage
->bytes_per_line
/ 2;
323 xrb
->origin2
= (GLushort
*) xrb
->ximage
->data
+ xrb
->width2
* (height
- 1);
325 /* Needed by PIXELADDR3 macro */
326 xrb
->width3
= xrb
->ximage
->bytes_per_line
;
327 xrb
->origin3
= (GLubyte
*) xrb
->ximage
->data
+ xrb
->width3
* (height
- 1);
329 /* Needed by PIXELADDR4 macro */
330 xrb
->width4
= xrb
->ximage
->width
;
331 xrb
->origin4
= (GLuint
*) xrb
->ximage
->data
+ xrb
->width4
* (height
- 1);
334 /* out of memory or buffer size is 0 x 0 */
335 xrb
->width1
= xrb
->width2
= xrb
->width3
= xrb
->width4
= 0;
342 if (!xrb
->St
.surface
|| !xrb
->St
.surface
->region
)
343 finish_surface_init(ctx
, xrb
);
345 xrb
->St
.surface
->width
= width
;
346 xrb
->St
.surface
->height
= height
;
353 * Called to create the front/back color renderbuffers, not user-created
356 struct xmesa_renderbuffer
*
357 xmesa_create_renderbuffer(GLcontext
*ctx
, GLuint name
, const GLvisual
*visual
,
358 GLboolean backBuffer
)
360 struct xmesa_renderbuffer
*xrb
= CALLOC_STRUCT(xmesa_renderbuffer
);
361 struct pipe_context
*pipe
= NULL
;/*ctx->st->pipe;*/
364 GLuint pipeFormat
= 0;
365 struct xmesa_surface
*xms
;
367 _mesa_init_renderbuffer(&xrb
->St
.Base
, name
);
369 xrb
->St
.Base
.Delete
= xmesa_delete_renderbuffer
;
371 xrb
->St
.Base
.AllocStorage
= xmesa_alloc_back_storage
;
373 xrb
->St
.Base
.AllocStorage
= xmesa_alloc_front_storage
;
375 if (visual
->rgbMode
) {
376 xrb
->St
.Base
.InternalFormat
= GL_RGBA
;
377 xrb
->St
.Base
._BaseFormat
= GL_RGBA
;
378 xrb
->St
.Base
.DataType
= GL_UNSIGNED_BYTE
;
379 xrb
->St
.Base
.RedBits
= visual
->redBits
;
380 xrb
->St
.Base
.GreenBits
= visual
->greenBits
;
381 xrb
->St
.Base
.BlueBits
= visual
->blueBits
;
382 xrb
->St
.Base
.AlphaBits
= visual
->alphaBits
;
383 pipeFormat
= PIPE_FORMAT_U_A8_R8_G8_B8
;
386 xrb
->St
.Base
.InternalFormat
= GL_COLOR_INDEX
;
387 xrb
->St
.Base
._BaseFormat
= GL_COLOR_INDEX
;
388 xrb
->St
.Base
.DataType
= GL_UNSIGNED_INT
;
389 xrb
->St
.Base
.IndexBits
= visual
->indexBits
;
391 /* only need to set Red/Green/EtcBits fields for user-created RBs */
393 xrb
->St
.surface
= xmesa_new_color_surface(pipe
, pipeFormat
);
394 xms
= (struct xmesa_surface
*) xrb
->St
.surface
;
402 struct gl_renderbuffer
*
403 xmesa_new_renderbuffer(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
404 GLenum internalFormat
, GLuint width
, GLuint height
)
406 struct xmesa_renderbuffer
*xrb
= CALLOC_STRUCT(xmesa_renderbuffer
);
409 _mesa_init_renderbuffer(&xrb
->St
.Base
, name
);
411 xrb
->St
.Base
.Delete
= xmesa_delete_renderbuffer
;
413 xrb
->St
.Base
.AllocStorage
= xmesa_alloc_back_storage
;
415 xrb
->St
.Base
.AllocStorage
= xmesa_alloc_front_storage
;
417 if (visual
->rgbMode
) {
418 xrb
->St
.Base
.InternalFormat
= GL_RGBA
;
419 xrb
->St
.Base
._BaseFormat
= GL_RGBA
;
420 xrb
->St
.Base
.DataType
= GL_UNSIGNED_BYTE
;
421 xrb
->St
.Base
.RedBits
= visual
->redBits
;
422 xrb
->St
.Base
.GreenBits
= visual
->greenBits
;
423 xrb
->St
.Base
.BlueBits
= visual
->blueBits
;
424 xrb
->St
.Base
.AlphaBits
= visual
->alphaBits
;
427 xrb
->St
.Base
.InternalFormat
= GL_COLOR_INDEX
;
428 xrb
->St
.Base
._BaseFormat
= GL_COLOR_INDEX
;
429 xrb
->St
.Base
.DataType
= GL_UNSIGNED_INT
;
430 xrb
->St
.Base
.IndexBits
= visual
->indexBits
;
432 /* only need to set Red/Green/EtcBits fields for user-created RBs */
440 * Called via gl_framebuffer::Delete() method when this buffer
441 * is _really_ being deleted.
444 xmesa_delete_framebuffer(struct gl_framebuffer
*fb
)
446 XMesaBuffer b
= XMESA_BUFFER(fb
);
448 if (b
->num_alloced
> 0) {
449 /* If no other buffer uses this X colormap then free the colors. */
450 if (!xmesa_find_buffer(b
->display
, b
->cmap
, b
)) {
453 if (b
->frontxrb
->drawable
)
454 client
= CLIENT_ID(b
->frontxrb
->drawable
->id
);
455 (void)FreeColors(b
->cmap
, client
,
456 b
->num_alloced
, b
->alloced_colors
, 0);
458 XFreeColors(b
->display
, b
->cmap
,
459 b
->alloced_colors
, b
->num_alloced
, 0);
465 XMesaFreeGC(b
->display
, b
->gc
);
467 XMesaFreeGC(b
->display
, b
->cleargc
);
469 XMesaFreeGC(b
->display
, b
->swapgc
);
471 if (fb
->Visual
.doubleBufferMode
) {
472 /* free back ximage/pixmap/shmregion */
473 if (b
->backxrb
->ximage
) {
474 #if defined(USE_XSHM) && !defined(XFree86Server)
476 XShmDetach( b
->display
, &b
->shminfo
);
477 XDestroyImage( b
->backxrb
->ximage
);
478 shmdt( b
->shminfo
.shmaddr
);
482 XMesaDestroyImage( b
->backxrb
->ximage
);
483 b
->backxrb
->ximage
= NULL
;
485 if (b
->backxrb
->pixmap
) {
486 XMesaFreePixmap( b
->display
, b
->backxrb
->pixmap
);
487 if (b
->xm_visual
->hpcr_clear_flag
) {
488 XMesaFreePixmap( b
->display
,
489 b
->xm_visual
->hpcr_clear_pixmap
);
490 XMesaDestroyImage( b
->xm_visual
->hpcr_clear_ximage
);
496 _mesa_free( b
->rowimage
->data
);
497 b
->rowimage
->data
= NULL
;
498 XMesaDestroyImage( b
->rowimage
);
501 _mesa_free_framebuffer_data(fb
);