Merge branch 'gallium-userbuf'
[mesa.git] / src / mesa / drivers / x11 / xm_dd.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25
26 /**
27 * \file xm_dd.h
28 * General device driver functions for Xlib driver.
29 */
30
31 #include "glxheader.h"
32 #include "main/bufferobj.h"
33 #include "main/context.h"
34 #include "main/colormac.h"
35 #include "main/fbobject.h"
36 #include "main/macros.h"
37 #include "main/image.h"
38 #include "main/imports.h"
39 #include "main/mtypes.h"
40 #include "main/pbo.h"
41 #include "main/texformat.h"
42 #include "swrast/swrast.h"
43 #include "swrast/s_context.h"
44 #include "swrast_setup/swrast_setup.h"
45 #include "tnl/tnl.h"
46 #include "tnl/t_context.h"
47 #include "drivers/common/meta.h"
48 #include "xmesaP.h"
49
50
51 static void
52 finish_or_flush( struct gl_context *ctx )
53 {
54 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
55 if (xmesa) {
56 _glthread_LOCK_MUTEX(_xmesa_lock);
57 XSync( xmesa->display, False );
58 _glthread_UNLOCK_MUTEX(_xmesa_lock);
59 }
60 }
61
62
63 /* Implements glColorMask() */
64 static void
65 color_mask(struct gl_context *ctx,
66 GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask)
67 {
68 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
69 XMesaBuffer xmbuf;
70 const int xclass = xmesa->xm_visual->visualType;
71 (void) amask;
72
73 if (_mesa_is_user_fbo(ctx->DrawBuffer))
74 return;
75
76 xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
77
78 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
79 unsigned long m;
80 if (rmask && gmask && bmask) {
81 m = ((unsigned long)~0L);
82 }
83 else {
84 m = 0;
85 if (rmask) m |= GET_REDMASK(xmesa->xm_visual);
86 if (gmask) m |= GET_GREENMASK(xmesa->xm_visual);
87 if (bmask) m |= GET_BLUEMASK(xmesa->xm_visual);
88 }
89 XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m );
90 }
91 }
92
93
94
95 /**********************************************************************/
96 /*** glClear implementations ***/
97 /**********************************************************************/
98
99
100 /**
101 * Clear the front or back color buffer, if it's implemented with a pixmap.
102 */
103 static void
104 clear_pixmap(struct gl_context *ctx, struct xmesa_renderbuffer *xrb,
105 GLint x, GLint y, GLint width, GLint height)
106 {
107 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
108 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
109
110 assert(xmbuf);
111 assert(xrb->pixmap);
112 assert(xmesa);
113 assert(xmesa->display);
114 assert(xrb->pixmap);
115 assert(xmbuf->cleargc);
116
117 XMesaFillRectangle( xmesa->display, xrb->pixmap, xmbuf->cleargc,
118 x, xrb->Base.Base.Height - y - height,
119 width, height );
120 }
121
122
123 static void
124 clear_16bit_ximage( struct gl_context *ctx, struct xmesa_renderbuffer *xrb,
125 GLint x, GLint y, GLint width, GLint height)
126 {
127 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
128 GLuint pixel = (GLuint) xmesa->clearpixel;
129 GLint i, j;
130
131 if (xmesa->swapbytes) {
132 pixel = ((pixel >> 8) & 0x00ff) | ((pixel << 8) & 0xff00);
133 }
134
135 for (j = 0; j < height; j++) {
136 GLushort *ptr2 = PIXEL_ADDR2(xrb, x, y + j);
137 for (i = 0; i < width; i++) {
138 ptr2[i] = pixel;
139 }
140 }
141 }
142
143
144 /* Optimized code provided by Nozomi Ytow <noz@xfree86.org> */
145 static void
146 clear_24bit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb,
147 GLint x, GLint y, GLint width, GLint height)
148 {
149 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
150 const GLubyte r = xmesa->clearcolor[0];
151 const GLubyte g = xmesa->clearcolor[1];
152 const GLubyte b = xmesa->clearcolor[2];
153
154 if (r == g && g == b) {
155 /* same value for all three components (gray) */
156 GLint j;
157 for (j = 0; j < height; j++) {
158 bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j);
159 memset(ptr3, r, 3 * width);
160 }
161 }
162 else {
163 /* non-gray clear color */
164 GLint i, j;
165 for (j = 0; j < height; j++) {
166 bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j);
167 for (i = 0; i < width; i++) {
168 ptr3->r = r;
169 ptr3->g = g;
170 ptr3->b = b;
171 ptr3++;
172 }
173 }
174 }
175 }
176
177
178 static void
179 clear_32bit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb,
180 GLint x, GLint y, GLint width, GLint height)
181 {
182 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
183 register GLuint pixel = (GLuint) xmesa->clearpixel;
184
185 if (!xrb->ximage)
186 return;
187
188 if (xmesa->swapbytes) {
189 pixel = ((pixel >> 24) & 0x000000ff)
190 | ((pixel >> 8) & 0x0000ff00)
191 | ((pixel << 8) & 0x00ff0000)
192 | ((pixel << 24) & 0xff000000);
193 }
194
195 if (width == xrb->Base.Base.Width && height == xrb->Base.Base.Height) {
196 /* clearing whole buffer */
197 const GLuint n = xrb->Base.Base.Width * xrb->Base.Base.Height;
198 GLuint *ptr4 = (GLuint *) xrb->ximage->data;
199 if (pixel == 0) {
200 /* common case */
201 memset(ptr4, pixel, 4 * n);
202 }
203 else {
204 GLuint i;
205 for (i = 0; i < n; i++)
206 ptr4[i] = pixel;
207 }
208 }
209 else {
210 /* clearing scissored region */
211 GLint i, j;
212 for (j = 0; j < height; j++) {
213 GLuint *ptr4 = PIXEL_ADDR4(xrb, x, y + j);
214 for (i = 0; i < width; i++) {
215 ptr4[i] = pixel;
216 }
217 }
218 }
219 }
220
221
222 static void
223 clear_nbit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb,
224 GLint x, GLint y, GLint width, GLint height)
225 {
226 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
227 XMesaImage *img = xrb->ximage;
228 GLint i, j;
229
230 /* TODO: optimize this */
231 y = YFLIP(xrb, y);
232 for (j = 0; j < height; j++) {
233 for (i = 0; i < width; i++) {
234 XMesaPutPixel(img, x+i, y-j, xmesa->clearpixel);
235 }
236 }
237 }
238
239
240
241 static void
242 clear_buffers(struct gl_context *ctx, GLbitfield buffers)
243 {
244 if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
245 /* this is a window system framebuffer */
246 const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask[0];
247 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
248 XMesaBuffer b = XMESA_BUFFER(ctx->DrawBuffer);
249 const GLint x = ctx->DrawBuffer->_Xmin;
250 const GLint y = ctx->DrawBuffer->_Ymin;
251 const GLint width = ctx->DrawBuffer->_Xmax - x;
252 const GLint height = ctx->DrawBuffer->_Ymax - y;
253
254 _mesa_unclamped_float_rgba_to_ubyte(xmesa->clearcolor,
255 ctx->Color.ClearColor.f);
256 xmesa->clearpixel = xmesa_color_to_pixel(ctx,
257 xmesa->clearcolor[0],
258 xmesa->clearcolor[1],
259 xmesa->clearcolor[2],
260 xmesa->clearcolor[3],
261 xmesa->xm_visual->undithered_pf);
262 XMesaSetForeground(xmesa->display, b->cleargc, xmesa->clearpixel);
263
264 /* we can't handle color or index masking */
265 if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) {
266 if (buffers & BUFFER_BIT_FRONT_LEFT) {
267 /* clear front color buffer */
268 struct gl_renderbuffer *frontRb
269 = ctx->DrawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
270 if (b->frontxrb == xmesa_renderbuffer(frontRb)) {
271 /* renderbuffer is not wrapped - great! */
272 b->frontxrb->clearFunc(ctx, b->frontxrb, x, y, width, height);
273 buffers &= ~BUFFER_BIT_FRONT_LEFT;
274 }
275 else {
276 /* we can't directly clear an alpha-wrapped color buffer */
277 }
278 }
279 if (buffers & BUFFER_BIT_BACK_LEFT) {
280 /* clear back color buffer */
281 struct gl_renderbuffer *backRb
282 = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
283 if (b->backxrb == xmesa_renderbuffer(backRb)) {
284 /* renderbuffer is not wrapped - great! */
285 b->backxrb->clearFunc(ctx, b->backxrb, x, y, width, height);
286 buffers &= ~BUFFER_BIT_BACK_LEFT;
287 }
288 }
289 }
290 }
291 if (buffers)
292 _swrast_Clear(ctx, buffers);
293 }
294
295
296 /* XXX these functions haven't been tested in the Xserver environment */
297
298
299 /**
300 * Check if we can do an optimized glDrawPixels into an 8R8G8B visual.
301 */
302 static GLboolean
303 can_do_DrawPixels_8R8G8B(struct gl_context *ctx, GLenum format, GLenum type)
304 {
305 if (format == GL_BGRA &&
306 type == GL_UNSIGNED_BYTE &&
307 ctx->DrawBuffer &&
308 _mesa_is_winsys_fbo(ctx->DrawBuffer) &&
309 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
310 ctx->Pixel.ZoomY == 1.0 &&
311 ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) {
312 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
313
314 if (swrast->NewState)
315 _swrast_validate_derived( ctx );
316
317 if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ {
318 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
319 if (rb) {
320 struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
321 if (xrb &&
322 xrb->pixmap && /* drawing to pixmap or window */
323 _mesa_get_format_bits(xrb->Base.Base.Format, GL_ALPHA_BITS) == 0) {
324 return GL_TRUE;
325 }
326 }
327 }
328 }
329 return GL_FALSE;
330 }
331
332
333 /**
334 * This function implements glDrawPixels() with an XPutImage call when
335 * drawing to the front buffer (X Window drawable).
336 * The image format must be GL_BGRA to match the PF_8R8G8B pixel format.
337 */
338 static void
339 xmesa_DrawPixels_8R8G8B( struct gl_context *ctx,
340 GLint x, GLint y, GLsizei width, GLsizei height,
341 GLenum format, GLenum type,
342 const struct gl_pixelstore_attrib *unpack,
343 const GLvoid *pixels )
344 {
345 if (can_do_DrawPixels_8R8G8B(ctx, format, type)) {
346 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
347 struct gl_pixelstore_attrib clippedUnpack = *unpack;
348 int dstX = x;
349 int dstY = y;
350 int w = width;
351 int h = height;
352
353 if (swrast->NewState)
354 _swrast_validate_derived( ctx );
355
356 if (_mesa_is_bufferobj(unpack->BufferObj)) {
357 /* unpack from PBO */
358 GLubyte *buf;
359 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
360 format, type, INT_MAX, pixels)) {
361 _mesa_error(ctx, GL_INVALID_OPERATION,
362 "glDrawPixels(invalid PBO access)");
363 return;
364 }
365 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
366 unpack->BufferObj->Size,
367 GL_MAP_READ_BIT,
368 unpack->BufferObj);
369 if (!buf) {
370 /* buffer is already mapped - that's an error */
371 _mesa_error(ctx, GL_INVALID_OPERATION,
372 "glDrawPixels(PBO is mapped)");
373 return;
374 }
375 pixels = ADD_POINTERS(buf, pixels);
376 }
377
378 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) {
379 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
380 XMesaDisplay *dpy = xmesa->xm_visual->display;
381 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
382 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */
383 struct xmesa_renderbuffer *xrb
384 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
385 const int srcX = clippedUnpack.SkipPixels;
386 const int srcY = clippedUnpack.SkipRows;
387 const int rowLength = clippedUnpack.RowLength;
388 XMesaImage ximage;
389
390 ASSERT(xmesa->xm_visual->dithered_pf == PF_8R8G8B);
391 ASSERT(xmesa->xm_visual->undithered_pf == PF_8R8G8B);
392 ASSERT(dpy);
393 ASSERT(gc);
394
395 /* This is a little tricky since all coordinates up to now have
396 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom
397 * so we have to carefully compute the Y coordinates/addresses here.
398 */
399 memset(&ximage, 0, sizeof(XMesaImage));
400 ximage.width = width;
401 ximage.height = height;
402 ximage.format = ZPixmap;
403 ximage.data = (char *) pixels
404 + ((srcY + h - 1) * rowLength + srcX) * 4;
405 ximage.byte_order = LSBFirst;
406 ximage.bitmap_unit = 32;
407 ximage.bitmap_bit_order = LSBFirst;
408 ximage.bitmap_pad = 32;
409 ximage.depth = 32;
410 ximage.bits_per_pixel = 32;
411 ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */
412 /* it seems we don't need to set the ximage.red/green/blue_mask fields */
413 /* flip Y axis for dest position */
414 dstY = YFLIP(xrb, dstY) - h + 1;
415 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h);
416 }
417
418 if (_mesa_is_bufferobj(unpack->BufferObj)) {
419 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
420 }
421 }
422 else {
423 /* software fallback */
424 _swrast_DrawPixels(ctx, x, y, width, height,
425 format, type, unpack, pixels);
426 }
427 }
428
429
430
431 /**
432 * Check if we can do an optimized glDrawPixels into an 5R6G5B visual.
433 */
434 static GLboolean
435 can_do_DrawPixels_5R6G5B(struct gl_context *ctx, GLenum format, GLenum type)
436 {
437 if (format == GL_RGB &&
438 type == GL_UNSIGNED_SHORT_5_6_5 &&
439 !ctx->Color.DitherFlag && /* no dithering */
440 ctx->DrawBuffer &&
441 _mesa_is_winsys_fbo(ctx->DrawBuffer) &&
442 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
443 ctx->Pixel.ZoomY == 1.0 &&
444 ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) {
445 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
446
447 if (swrast->NewState)
448 _swrast_validate_derived( ctx );
449
450 if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ {
451 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
452 if (rb) {
453 struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
454 if (xrb &&
455 xrb->pixmap && /* drawing to pixmap or window */
456 _mesa_get_format_bits(xrb->Base.Base.Format, GL_ALPHA_BITS) == 0) {
457 return GL_TRUE;
458 }
459 }
460 }
461 }
462 return GL_FALSE;
463 }
464
465
466 /**
467 * This function implements glDrawPixels() with an XPutImage call when
468 * drawing to the front buffer (X Window drawable). The image format
469 * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to
470 * match the PF_5R6G5B pixel format.
471 */
472 static void
473 xmesa_DrawPixels_5R6G5B( struct gl_context *ctx,
474 GLint x, GLint y, GLsizei width, GLsizei height,
475 GLenum format, GLenum type,
476 const struct gl_pixelstore_attrib *unpack,
477 const GLvoid *pixels )
478 {
479 if (can_do_DrawPixels_5R6G5B(ctx, format, type)) {
480 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
481 struct gl_pixelstore_attrib clippedUnpack = *unpack;
482 int dstX = x;
483 int dstY = y;
484 int w = width;
485 int h = height;
486
487 if (swrast->NewState)
488 _swrast_validate_derived( ctx );
489
490 if (_mesa_is_bufferobj(unpack->BufferObj)) {
491 /* unpack from PBO */
492 GLubyte *buf;
493 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
494 format, type, INT_MAX, pixels)) {
495 _mesa_error(ctx, GL_INVALID_OPERATION,
496 "glDrawPixels(invalid PBO access)");
497 return;
498 }
499 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
500 unpack->BufferObj->Size,
501 GL_MAP_READ_BIT,
502 unpack->BufferObj);
503 if (!buf) {
504 /* buffer is already mapped - that's an error */
505 _mesa_error(ctx, GL_INVALID_OPERATION,
506 "glDrawPixels(PBO is mapped)");
507 return;
508 }
509 pixels = ADD_POINTERS(buf, pixels);
510 }
511
512 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) {
513 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
514 XMesaDisplay *dpy = xmesa->xm_visual->display;
515 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
516 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */
517 struct xmesa_renderbuffer *xrb
518 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
519 const int srcX = clippedUnpack.SkipPixels;
520 const int srcY = clippedUnpack.SkipRows;
521 const int rowLength = clippedUnpack.RowLength;
522 XMesaImage ximage;
523
524 ASSERT(xmesa->xm_visual->undithered_pf == PF_5R6G5B);
525 ASSERT(dpy);
526 ASSERT(gc);
527
528 /* This is a little tricky since all coordinates up to now have
529 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom
530 * so we have to carefully compute the Y coordinates/addresses here.
531 */
532 memset(&ximage, 0, sizeof(XMesaImage));
533 ximage.width = width;
534 ximage.height = height;
535 ximage.format = ZPixmap;
536 ximage.data = (char *) pixels
537 + ((srcY + h - 1) * rowLength + srcX) * 2;
538 ximage.byte_order = LSBFirst;
539 ximage.bitmap_unit = 16;
540 ximage.bitmap_bit_order = LSBFirst;
541 ximage.bitmap_pad = 16;
542 ximage.depth = 16;
543 ximage.bits_per_pixel = 16;
544 ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */
545 /* it seems we don't need to set the ximage.red/green/blue_mask fields */
546 /* flip Y axis for dest position */
547 dstY = YFLIP(xrb, dstY) - h + 1;
548 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h);
549 }
550
551 if (unpack->BufferObj->Name) {
552 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
553 }
554 }
555 else {
556 /* software fallback */
557 _swrast_DrawPixels(ctx, x, y, width, height,
558 format, type, unpack, pixels);
559 }
560 }
561
562
563 /**
564 * Determine if we can do an optimized glCopyPixels.
565 */
566 static GLboolean
567 can_do_CopyPixels(struct gl_context *ctx, GLenum type)
568 {
569 if (type == GL_COLOR &&
570 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
571 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
572 ctx->Pixel.ZoomY == 1.0 &&
573 ctx->Color.DrawBuffer[0] == GL_FRONT && /* copy to front buf */
574 ctx->Pixel.ReadBuffer == GL_FRONT && /* copy from front buf */
575 ctx->ReadBuffer->_ColorReadBuffer &&
576 ctx->DrawBuffer->_ColorDrawBuffers[0]) {
577 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
578
579 if (swrast->NewState)
580 _swrast_validate_derived( ctx );
581
582 if ((swrast->_RasterMask & ~CLIP_BIT) == 0x0 &&
583 ctx->ReadBuffer &&
584 ctx->ReadBuffer->_ColorReadBuffer &&
585 ctx->DrawBuffer &&
586 ctx->DrawBuffer->_ColorDrawBuffers[0]) {
587 struct xmesa_renderbuffer *srcXrb
588 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
589 struct xmesa_renderbuffer *dstXrb
590 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
591 if (srcXrb->pixmap && dstXrb->pixmap) {
592 return GL_TRUE;
593 }
594 }
595 }
596 return GL_FALSE;
597 }
598
599
600 /**
601 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
602 * for the color buffer. Don't support zooming, pixel transfer, etc.
603 * We do support copying from one window to another, ala glXMakeCurrentRead.
604 */
605 static void
606 xmesa_CopyPixels( struct gl_context *ctx,
607 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
608 GLint destx, GLint desty, GLenum type )
609 {
610 if (can_do_CopyPixels(ctx, type)) {
611 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
612 XMesaDisplay *dpy = xmesa->xm_visual->display;
613 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
614 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */
615 struct xmesa_renderbuffer *srcXrb
616 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
617 struct xmesa_renderbuffer *dstXrb
618 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
619
620 ASSERT(dpy);
621 ASSERT(gc);
622
623 /* Note: we don't do any special clipping work here. We could,
624 * but X will do it for us.
625 */
626 srcy = YFLIP(srcXrb, srcy) - height + 1;
627 desty = YFLIP(dstXrb, desty) - height + 1;
628 XCopyArea(dpy, srcXrb->pixmap, dstXrb->pixmap, gc,
629 srcx, srcy, width, height, destx, desty);
630 }
631 else {
632 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type );
633 }
634 }
635
636
637
638
639 /*
640 * Every driver should implement a GetString function in order to
641 * return a meaningful GL_RENDERER string.
642 */
643 static const GLubyte *
644 get_string( struct gl_context *ctx, GLenum name )
645 {
646 (void) ctx;
647 switch (name) {
648 case GL_RENDERER:
649 return (const GLubyte *) "Mesa X11";
650 case GL_VENDOR:
651 return NULL;
652 default:
653 return NULL;
654 }
655 }
656
657
658 /*
659 * We implement the glEnable function only because we care about
660 * dither enable/disable.
661 */
662 static void
663 enable( struct gl_context *ctx, GLenum pname, GLboolean state )
664 {
665 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
666
667 switch (pname) {
668 case GL_DITHER:
669 if (state)
670 xmesa->pixelformat = xmesa->xm_visual->dithered_pf;
671 else
672 xmesa->pixelformat = xmesa->xm_visual->undithered_pf;
673 break;
674 default:
675 ; /* silence compiler warning */
676 }
677 }
678
679
680 /**
681 * Called when the driver should update its state, based on the new_state
682 * flags.
683 */
684 void
685 xmesa_update_state( struct gl_context *ctx, GLbitfield new_state )
686 {
687 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
688
689 /* Propagate statechange information to swrast and swrast_setup
690 * modules. The X11 driver has no internal GL-dependent state.
691 */
692 _swrast_InvalidateState( ctx, new_state );
693 _tnl_InvalidateState( ctx, new_state );
694 _vbo_InvalidateState( ctx, new_state );
695 _swsetup_InvalidateState( ctx, new_state );
696
697 if (_mesa_is_user_fbo(ctx->DrawBuffer))
698 return;
699
700 /*
701 * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect
702 * renderbuffer span/clear funcs.
703 * Check _NEW_COLOR to detect dither enable/disable.
704 */
705 if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) {
706 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
707 struct xmesa_renderbuffer *front_xrb, *back_xrb;
708
709 front_xrb = xmbuf->frontxrb;
710 if (front_xrb) {
711 front_xrb->clearFunc = clear_pixmap;
712 }
713
714 back_xrb = xmbuf->backxrb;
715 if (back_xrb) {
716 if (xmbuf->backxrb->pixmap) {
717 back_xrb->clearFunc = clear_pixmap;
718 }
719 else {
720 switch (xmesa->xm_visual->BitsPerPixel) {
721 case 16:
722 back_xrb->clearFunc = clear_16bit_ximage;
723 break;
724 case 24:
725 back_xrb->clearFunc = clear_24bit_ximage;
726 break;
727 case 32:
728 back_xrb->clearFunc = clear_32bit_ximage;
729 break;
730 default:
731 back_xrb->clearFunc = clear_nbit_ximage;
732 break;
733 }
734 }
735 }
736 }
737 }
738
739
740
741 /**
742 * In SW, we don't really compress GL_COMPRESSED_RGB[A] textures!
743 */
744 static gl_format
745 choose_tex_format( struct gl_context *ctx, GLint internalFormat,
746 GLenum format, GLenum type )
747 {
748 switch (internalFormat) {
749 case GL_COMPRESSED_RGB_ARB:
750 return MESA_FORMAT_RGB888;
751 case GL_COMPRESSED_RGBA_ARB:
752 return MESA_FORMAT_RGBA8888;
753 default:
754 return _mesa_choose_tex_format(ctx, internalFormat, format, type);
755 }
756 }
757
758
759 /**
760 * Called by glViewport.
761 * This is a good time for us to poll the current X window size and adjust
762 * our renderbuffers to match the current window size.
763 * Remember, we have no opportunity to respond to conventional
764 * X Resize/StructureNotify events since the X driver has no event loop.
765 * Thus, we poll.
766 * Note that this trick isn't fool-proof. If the application never calls
767 * glViewport, our notion of the current window size may be incorrect.
768 * That problem led to the GLX_MESA_resize_buffers extension.
769 */
770 static void
771 xmesa_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
772 {
773 XMesaContext xmctx = XMESA_CONTEXT(ctx);
774 XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer);
775 XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer);
776 xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf);
777 xmesa_check_and_update_buffer_size(xmctx, xmreadbuf);
778 (void) x;
779 (void) y;
780 (void) w;
781 (void) h;
782 }
783
784
785 #if ENABLE_EXT_timer_query
786
787 /*
788 * The GL_EXT_timer_query extension is not enabled for the XServer
789 * indirect renderer. Not sure about how/if wrapping of gettimeofday()
790 * is done, etc.
791 */
792
793 struct xmesa_query_object
794 {
795 struct gl_query_object Base;
796 struct timeval StartTime;
797 };
798
799
800 static struct gl_query_object *
801 xmesa_new_query_object(struct gl_context *ctx, GLuint id)
802 {
803 struct xmesa_query_object *q = CALLOC_STRUCT(xmesa_query_object);
804 if (q) {
805 q->Base.Id = id;
806 q->Base.Ready = GL_TRUE;
807 }
808 return &q->Base;
809 }
810
811
812 static void
813 xmesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
814 {
815 if (q->Target == GL_TIME_ELAPSED_EXT) {
816 struct xmesa_query_object *xq = (struct xmesa_query_object *) q;
817 (void) gettimeofday(&xq->StartTime, NULL);
818 }
819 }
820
821
822 /**
823 * Return the difference between the two given times in microseconds.
824 */
825 #ifdef __VMS
826 #define suseconds_t unsigned int
827 #endif
828 static GLuint64EXT
829 time_diff(const struct timeval *t0, const struct timeval *t1)
830 {
831 GLuint64EXT seconds0 = t0->tv_sec & 0xff; /* 0 .. 255 seconds */
832 GLuint64EXT seconds1 = t1->tv_sec & 0xff; /* 0 .. 255 seconds */
833 GLuint64EXT nanosec0 = (seconds0 * 1000000 + t0->tv_usec) * 1000;
834 GLuint64EXT nanosec1 = (seconds1 * 1000000 + t1->tv_usec) * 1000;
835 return nanosec1 - nanosec0;
836 }
837
838
839 static void
840 xmesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
841 {
842 if (q->Target == GL_TIME_ELAPSED_EXT) {
843 struct xmesa_query_object *xq = (struct xmesa_query_object *) q;
844 struct timeval endTime;
845 (void) gettimeofday(&endTime, NULL);
846 /* result is in nanoseconds! */
847 q->Result = time_diff(&xq->StartTime, &endTime);
848 }
849 q->Ready = GL_TRUE;
850 }
851
852 #endif /* ENABLE_timer_query */
853
854
855 /**
856 * Initialize the device driver function table with the functions
857 * we implement in this driver.
858 */
859 void
860 xmesa_init_driver_functions( XMesaVisual xmvisual,
861 struct dd_function_table *driver )
862 {
863 driver->GetString = get_string;
864 driver->UpdateState = xmesa_update_state;
865 driver->GetBufferSize = NULL; /* OBSOLETE */
866 driver->Flush = finish_or_flush;
867 driver->Finish = finish_or_flush;
868 driver->ColorMask = color_mask;
869 driver->Enable = enable;
870 driver->Viewport = xmesa_viewport;
871 if (TEST_META_FUNCS) {
872 driver->Clear = _mesa_meta_Clear;
873 driver->CopyPixels = _mesa_meta_CopyPixels;
874 driver->BlitFramebuffer = _mesa_meta_BlitFramebuffer;
875 driver->DrawPixels = _mesa_meta_DrawPixels;
876 driver->Bitmap = _mesa_meta_Bitmap;
877 }
878 else {
879 driver->Clear = clear_buffers;
880 driver->CopyPixels = xmesa_CopyPixels;
881 if (xmvisual->undithered_pf == PF_8R8G8B &&
882 xmvisual->dithered_pf == PF_8R8G8B &&
883 xmvisual->BitsPerPixel == 32) {
884 driver->DrawPixels = xmesa_DrawPixels_8R8G8B;
885 }
886 else if (xmvisual->undithered_pf == PF_5R6G5B) {
887 driver->DrawPixels = xmesa_DrawPixels_5R6G5B;
888 }
889 }
890
891 driver->MapRenderbuffer = xmesa_MapRenderbuffer;
892 driver->UnmapRenderbuffer = xmesa_UnmapRenderbuffer;
893
894 #if ENABLE_EXT_texure_compression_s3tc
895 driver->ChooseTextureFormat = choose_tex_format;
896 #else
897 (void) choose_tex_format;
898 #endif
899
900 #if ENABLE_EXT_timer_query
901 driver->NewQueryObject = xmesa_new_query_object;
902 driver->BeginQuery = xmesa_begin_query;
903 driver->EndQuery = xmesa_end_query;
904 #endif
905 }
906
907
908 #define XMESA_NEW_POINT (_NEW_POINT | \
909 _NEW_RENDERMODE | \
910 _SWRAST_NEW_RASTERMASK)
911
912 #define XMESA_NEW_LINE (_NEW_LINE | \
913 _NEW_TEXTURE | \
914 _NEW_LIGHT | \
915 _NEW_DEPTH | \
916 _NEW_RENDERMODE | \
917 _SWRAST_NEW_RASTERMASK)
918
919 #define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \
920 _NEW_TEXTURE | \
921 _NEW_LIGHT | \
922 _NEW_DEPTH | \
923 _NEW_RENDERMODE | \
924 _SWRAST_NEW_RASTERMASK)
925
926
927 /**
928 * Extend the software rasterizer with our line/point/triangle
929 * functions.
930 * Called during context creation only.
931 */
932 void xmesa_register_swrast_functions( struct gl_context *ctx )
933 {
934 SWcontext *swrast = SWRAST_CONTEXT( ctx );
935
936 swrast->choose_point = xmesa_choose_point;
937 swrast->choose_line = xmesa_choose_line;
938 swrast->choose_triangle = xmesa_choose_triangle;
939
940 /* XXX these lines have no net effect. Remove??? */
941 swrast->InvalidatePointMask |= XMESA_NEW_POINT;
942 swrast->InvalidateLineMask |= XMESA_NEW_LINE;
943 swrast->InvalidateTriangleMask |= XMESA_NEW_TRIANGLE;
944 }