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