Fix a front/back CopyPixels glitch.
[mesa.git] / src / mesa / drivers / x11 / xm_dd.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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 #include "glxheader.h"
27 #include "bufferobj.h"
28 #include "context.h"
29 #include "colormac.h"
30 #include "depth.h"
31 #include "drawpix.h"
32 #include "extensions.h"
33 #include "macros.h"
34 #include "imports.h"
35 #include "mtypes.h"
36 #include "state.h"
37 #include "texobj.h"
38 #include "teximage.h"
39 #include "texstore.h"
40 #include "texformat.h"
41 #include "xmesaP.h"
42 #include "array_cache/acache.h"
43 #include "swrast/swrast.h"
44 #include "swrast/s_context.h"
45 #include "swrast/s_drawpix.h"
46 #include "swrast/s_alphabuf.h"
47 #include "swrast_setup/swrast_setup.h"
48 #include "tnl/tnl.h"
49 #include "tnl/t_context.h"
50 #include "tnl/t_pipeline.h"
51
52
53 /*
54 * Return the size (width, height) of the X window for the given GLframebuffer.
55 * Output: width - width of buffer in pixels.
56 * height - height of buffer in pixels.
57 */
58 static void
59 get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
60 {
61 /* We can do this cast because the first field in the XMesaBuffer
62 * struct is a GLframebuffer struct. If this weren't true, we'd
63 * need a pointer from the GLframebuffer to the XMesaBuffer.
64 */
65 const XMesaBuffer xmBuffer = (XMesaBuffer) buffer;
66 unsigned int winwidth, winheight;
67 #ifdef XFree86Server
68 /* XFree86 GLX renderer */
69 if (xmBuffer->frontbuffer->width > MAX_WIDTH ||
70 xmBuffer->frontbuffer->height > MAX_HEIGHT) {
71 winwidth = buffer->Width;
72 winheight = buffer->Height;
73 } else {
74 winwidth = xmBuffer->frontbuffer->width;
75 winheight = xmBuffer->frontbuffer->height;
76 }
77 #else
78 Window root;
79 int winx, winy;
80 unsigned int bw, d;
81
82 _glthread_LOCK_MUTEX(_xmesa_lock);
83 XSync(xmBuffer->xm_visual->display, 0); /* added for Chromium */
84 XGetGeometry( xmBuffer->xm_visual->display, xmBuffer->frontbuffer, &root,
85 &winx, &winy, &winwidth, &winheight, &bw, &d );
86 _glthread_UNLOCK_MUTEX(_xmesa_lock);
87 #endif
88
89 (void)kernel8; /* Muffle compiler */
90
91 *width = winwidth;
92 *height = winheight;
93 }
94
95
96 static void
97 finish_or_flush( GLcontext *ctx )
98 {
99 #ifdef XFree86Server
100 /* NOT_NEEDED */
101 #else
102 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
103 if (xmesa) {
104 _glthread_LOCK_MUTEX(_xmesa_lock);
105 XSync( xmesa->display, False );
106 _glthread_UNLOCK_MUTEX(_xmesa_lock);
107 }
108 #endif
109 }
110
111
112
113 /*
114 * This chooses the color buffer for reading and writing spans, points,
115 * lines, and triangles.
116 */
117 static void
118 set_buffer( GLcontext *ctx, GLframebuffer *buffer, GLuint bufferBit )
119 {
120 /* We can make this cast since the XMesaBuffer wraps GLframebuffer.
121 * GLframebuffer is the first member in a XMesaBuffer struct.
122 */
123 XMesaBuffer target = (XMesaBuffer) buffer;
124 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
125
126 /* This assignment tells the span/point/line/triangle functions
127 * which XMesaBuffer to use.
128 */
129 xmesa->xm_buffer = target;
130
131 /*
132 * Now determine front vs back color buffer.
133 */
134 if (bufferBit == FRONT_LEFT_BIT) {
135 target->buffer = target->frontbuffer;
136 }
137 else if (bufferBit == BACK_LEFT_BIT) {
138 ASSERT(target->db_state);
139 if (target->backpixmap) {
140 /* back buffer is a pixmap */
141 target->buffer = (XMesaDrawable) target->backpixmap;
142 }
143 else if (target->backimage) {
144 /* back buffer is an XImage */
145 target->buffer = None;
146 }
147 else {
148 /* No back buffer!!!! Must be out of memory, use front buffer */
149 target->buffer = target->frontbuffer;
150 }
151 }
152 else {
153 _mesa_problem(ctx, "invalid buffer 0x%x in set_buffer() in xm_dd.c");
154 return;
155 }
156 xmesa_update_span_funcs(ctx);
157 }
158
159
160
161 static void
162 clear_index( GLcontext *ctx, GLuint index )
163 {
164 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
165 xmesa->clearpixel = (unsigned long) index;
166 XMesaSetForeground( xmesa->display, xmesa->xm_draw_buffer->cleargc,
167 (unsigned long) index );
168 }
169
170
171 static void
172 clear_color( GLcontext *ctx, const GLfloat color[4] )
173 {
174 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
175 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]);
176 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]);
177 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]);
178 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]);
179 xmesa->clearpixel = xmesa_color_to_pixel( xmesa,
180 xmesa->clearcolor[0],
181 xmesa->clearcolor[1],
182 xmesa->clearcolor[2],
183 xmesa->clearcolor[3],
184 xmesa->xm_visual->undithered_pf );
185 _glthread_LOCK_MUTEX(_xmesa_lock);
186 XMesaSetForeground( xmesa->display, xmesa->xm_draw_buffer->cleargc,
187 xmesa->clearpixel );
188 _glthread_UNLOCK_MUTEX(_xmesa_lock);
189 }
190
191
192
193 /* Set index mask ala glIndexMask */
194 static void
195 index_mask( GLcontext *ctx, GLuint mask )
196 {
197 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
198 if (xmesa->xm_draw_buffer->buffer != XIMAGE) {
199 unsigned long m;
200 if (mask==0xffffffff) {
201 m = ((unsigned long)~0L);
202 }
203 else {
204 m = (unsigned long) mask;
205 }
206 XMesaSetPlaneMask( xmesa->display, xmesa->xm_draw_buffer->cleargc, m );
207 XMesaSetPlaneMask( xmesa->display, xmesa->xm_draw_buffer->gc, m );
208 }
209 }
210
211
212 /* Implements glColorMask() */
213 static void
214 color_mask(GLcontext *ctx,
215 GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask)
216 {
217 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
218 int xclass = GET_VISUAL_CLASS(xmesa->xm_visual);
219 (void) amask;
220
221 if (xclass == TrueColor || xclass == DirectColor) {
222 unsigned long m;
223 if (rmask && gmask && bmask) {
224 m = ((unsigned long)~0L);
225 }
226 else {
227 m = 0;
228 if (rmask) m |= GET_REDMASK(xmesa->xm_visual);
229 if (gmask) m |= GET_GREENMASK(xmesa->xm_visual);
230 if (bmask) m |= GET_BLUEMASK(xmesa->xm_visual);
231 }
232 XMesaSetPlaneMask( xmesa->display, xmesa->xm_draw_buffer->cleargc, m );
233 XMesaSetPlaneMask( xmesa->display, xmesa->xm_draw_buffer->gc, m );
234 }
235 }
236
237
238
239 /**********************************************************************/
240 /*** glClear implementations ***/
241 /**********************************************************************/
242
243
244 static void
245 clear_front_pixmap( GLcontext *ctx, GLboolean all,
246 GLint x, GLint y, GLint width, GLint height )
247 {
248 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
249 if (all) {
250 XMesaFillRectangle( xmesa->display, xmesa->xm_draw_buffer->frontbuffer,
251 xmesa->xm_draw_buffer->cleargc,
252 0, 0,
253 xmesa->xm_draw_buffer->width+1,
254 xmesa->xm_draw_buffer->height+1 );
255 }
256 else {
257 XMesaFillRectangle( xmesa->display, xmesa->xm_draw_buffer->frontbuffer,
258 xmesa->xm_draw_buffer->cleargc,
259 x, xmesa->xm_draw_buffer->height - y - height,
260 width, height );
261 }
262 }
263
264
265 static void
266 clear_back_pixmap( GLcontext *ctx, GLboolean all,
267 GLint x, GLint y, GLint width, GLint height )
268 {
269 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
270 if (all) {
271 XMesaFillRectangle( xmesa->display, xmesa->xm_draw_buffer->backpixmap,
272 xmesa->xm_draw_buffer->cleargc,
273 0, 0,
274 xmesa->xm_draw_buffer->width+1,
275 xmesa->xm_draw_buffer->height+1 );
276 }
277 else {
278 XMesaFillRectangle( xmesa->display, xmesa->xm_draw_buffer->backpixmap,
279 xmesa->xm_draw_buffer->cleargc,
280 x, xmesa->xm_draw_buffer->height - y - height,
281 width, height );
282 }
283 }
284
285
286 static void
287 clear_8bit_ximage( GLcontext *ctx, GLboolean all,
288 GLint x, GLint y, GLint width, GLint height )
289 {
290 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
291 if (all) {
292 size_t n = xmesa->xm_draw_buffer->backimage->bytes_per_line
293 * xmesa->xm_draw_buffer->backimage->height;
294 MEMSET( xmesa->xm_draw_buffer->backimage->data, xmesa->clearpixel, n );
295 }
296 else {
297 GLint i;
298 for (i=0;i<height;i++) {
299 GLubyte *ptr = PIXELADDR1( xmesa->xm_draw_buffer, x, y+i );
300 MEMSET( ptr, xmesa->clearpixel, width );
301 }
302 }
303 }
304
305
306 static void
307 clear_HPCR_ximage( GLcontext *ctx, GLboolean all,
308 GLint x, GLint y, GLint width, GLint height )
309 {
310 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
311 if (all) {
312 GLint i, c16 = (xmesa->xm_draw_buffer->backimage->bytes_per_line>>4)<<4;
313 GLubyte *ptr = (GLubyte *)xmesa->xm_draw_buffer->backimage->data;
314 for (i=0; i<xmesa->xm_draw_buffer->backimage->height; i++) {
315 GLint j;
316 GLubyte *sptr = xmesa->xm_visual->hpcr_clear_ximage_pattern[0];
317 if (i&1) {
318 sptr += 16;
319 }
320 for (j=0; j<c16; j+=16) {
321 ptr[0] = sptr[0];
322 ptr[1] = sptr[1];
323 ptr[2] = sptr[2];
324 ptr[3] = sptr[3];
325 ptr[4] = sptr[4];
326 ptr[5] = sptr[5];
327 ptr[6] = sptr[6];
328 ptr[7] = sptr[7];
329 ptr[8] = sptr[8];
330 ptr[9] = sptr[9];
331 ptr[10] = sptr[10];
332 ptr[11] = sptr[11];
333 ptr[12] = sptr[12];
334 ptr[13] = sptr[13];
335 ptr[14] = sptr[14];
336 ptr[15] = sptr[15];
337 ptr += 16;
338 }
339 for (; j<xmesa->xm_draw_buffer->backimage->bytes_per_line; j++) {
340 *ptr = sptr[j&15];
341 ptr++;
342 }
343 }
344 }
345 else {
346 GLint i;
347 for (i=y; i<y+height; i++) {
348 GLubyte *ptr = PIXELADDR1( xmesa->xm_draw_buffer, x, i );
349 int j;
350 GLubyte *sptr = xmesa->xm_visual->hpcr_clear_ximage_pattern[0];
351 if (i&1) {
352 sptr += 16;
353 }
354 for (j=x; j<x+width; j++) {
355 *ptr = sptr[j&15];
356 ptr++;
357 }
358 }
359 }
360 }
361
362
363 static void
364 clear_16bit_ximage( GLcontext *ctx, GLboolean all,
365 GLint x, GLint y, GLint width, GLint height )
366 {
367 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
368 register GLuint pixel = (GLuint) xmesa->clearpixel;
369 if (xmesa->swapbytes) {
370 pixel = ((pixel >> 8) & 0x00ff) | ((pixel << 8) & 0xff00);
371 }
372 if (all) {
373 register GLuint n;
374 register GLuint *ptr4 = (GLuint *) xmesa->xm_draw_buffer->backimage->data;
375 if ((pixel & 0xff) == ((pixel >> 8) & 0xff)) {
376 /* low and high bytes are equal so use memset() */
377 n = xmesa->xm_draw_buffer->backimage->bytes_per_line
378 * xmesa->xm_draw_buffer->height;
379 MEMSET( ptr4, pixel & 0xff, n );
380 }
381 else {
382 pixel = pixel | (pixel<<16);
383 n = xmesa->xm_draw_buffer->backimage->bytes_per_line
384 * xmesa->xm_draw_buffer->height / 4;
385 do {
386 *ptr4++ = pixel;
387 n--;
388 } while (n!=0);
389
390 if ((xmesa->xm_draw_buffer->backimage->bytes_per_line *
391 xmesa->xm_draw_buffer->height) & 0x2)
392 *(GLushort *)ptr4 = pixel & 0xffff;
393 }
394 }
395 else {
396 register int i, j;
397 for (j=0;j<height;j++) {
398 register GLushort *ptr2 = PIXELADDR2( xmesa->xm_draw_buffer, x, y+j );
399 for (i=0;i<width;i++) {
400 *ptr2++ = pixel;
401 }
402 }
403 }
404 }
405
406
407 /* Optimized code provided by Nozomi Ytow <noz@xfree86.org> */
408 static void
409 clear_24bit_ximage( GLcontext *ctx, GLboolean all,
410 GLint x, GLint y, GLint width, GLint height )
411 {
412 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
413 const GLubyte r = xmesa->clearcolor[0];
414 const GLubyte g = xmesa->clearcolor[1];
415 const GLubyte b = xmesa->clearcolor[2];
416 #if 0 /* See below */
417 register GLuint clearPixel;
418 if (xmesa->swapbytes) {
419 clearPixel = (b << 16) | (g << 8) | r;
420 }
421 else {
422 clearPixel = (r << 16) | (g << 8) | b;
423 }
424 #endif
425
426 if (all) {
427 if (r==g && g==b) {
428 /* same value for all three components (gray) */
429 const GLint w3 = xmesa->xm_draw_buffer->width * 3;
430 const GLint h = xmesa->xm_draw_buffer->height;
431 GLint i;
432 for (i = 0; i < h; i++) {
433 bgr_t *ptr3 = PIXELADDR3(xmesa->xm_draw_buffer, 0, i);
434 MEMSET(ptr3, r, w3);
435 }
436 }
437 else {
438 /* the usual case */
439 const GLint w = xmesa->xm_draw_buffer->width;
440 const GLint h = xmesa->xm_draw_buffer->height;
441 GLint i, j;
442 for (i = 0; i < h; i++) {
443 bgr_t *ptr3 = PIXELADDR3(xmesa->xm_draw_buffer, 0, i);
444 for (j = 0; j < w; j++) {
445 ptr3->r = r;
446 ptr3->g = g;
447 ptr3->b = b;
448 ptr3++;
449 }
450 }
451 #if 0 /* this code doesn't work for all window widths */
452 register GLuint *ptr4 = (GLuint *) ptr3;
453 register GLuint px;
454 GLuint pixel4[3];
455 register GLuint *p = pixel4;
456 pixel4[0] = clearPixel | (clearPixel << 24);
457 pixel4[1] = (clearPixel << 16) | (clearPixel >> 8);
458 pixel4[2] = (clearPixel << 8) | (clearPixel >> 16);
459 switch (3 & (int)(ptr3 - (bgr_t*) ptr4)){
460 case 0:
461 break;
462 case 1:
463 px = *ptr4 & 0x00ffffff;
464 px |= pixel4[0] & 0xff000000;
465 *ptr4++ = px;
466 px = *ptr4 & 0xffff0000;
467 px |= pixel4[2] & 0x0000ffff;
468 *ptr4 = px;
469 if (0 == --n)
470 break;
471 case 2:
472 px = *ptr4 & 0x0000fffff;
473 px |= pixel4[1] & 0xffff0000;
474 *ptr4++ = px;
475 px = *ptr4 & 0xffffff00;
476 px |= pixel4[2] & 0x000000ff;
477 *ptr4 = px;
478 if (0 == --n)
479 break;
480 case 3:
481 px = *ptr4 & 0x000000ff;
482 px |= pixel4[2] & 0xffffff00;
483 *ptr4++ = px;
484 --n;
485 break;
486 }
487 while (n > 3) {
488 p = pixel4;
489 *ptr4++ = *p++;
490 *ptr4++ = *p++;
491 *ptr4++ = *p++;
492 n -= 4;
493 }
494 switch (n) {
495 case 3:
496 p = pixel4;
497 *ptr4++ = *p++;
498 *ptr4++ = *p++;
499 px = *ptr4 & 0xffffff00;
500 px |= clearPixel & 0xff;
501 *ptr4 = px;
502 break;
503 case 2:
504 p = pixel4;
505 *ptr4++ = *p++;
506 px = *ptr4 & 0xffff0000;
507 px |= *p & 0xffff;
508 *ptr4 = px;
509 break;
510 case 1:
511 px = *ptr4 & 0xff000000;
512 px |= *p & 0xffffff;
513 *ptr4 = px;
514 break;
515 case 0:
516 break;
517 }
518 #endif
519 }
520 }
521 else {
522 /* only clear subrect of color buffer */
523 if (r==g && g==b) {
524 /* same value for all three components (gray) */
525 GLint j;
526 for (j=0;j<height;j++) {
527 bgr_t *ptr3 = PIXELADDR3( xmesa->xm_draw_buffer, x, y+j );
528 MEMSET(ptr3, r, 3 * width);
529 }
530 }
531 else {
532 /* non-gray clear color */
533 GLint i, j;
534 for (j = 0; j < height; j++) {
535 bgr_t *ptr3 = PIXELADDR3( xmesa->xm_draw_buffer, x, y+j );
536 for (i = 0; i < width; i++) {
537 ptr3->r = r;
538 ptr3->g = g;
539 ptr3->b = b;
540 ptr3++;
541 }
542 }
543 #if 0 /* this code might not always (seems ptr3 always == ptr4) */
544 GLint j;
545 GLuint pixel4[3];
546 pixel4[0] = clearPixel | (clearPixel << 24);
547 pixel4[1] = (clearPixel << 16) | (clearPixel >> 8);
548 pixel4[2] = (clearPixel << 8) | (clearPixel >> 16);
549 for (j=0;j<height;j++) {
550 bgr_t *ptr3 = PIXELADDR3( xmesa->xm_draw_buffer, x, y+j );
551 register GLuint *ptr4 = (GLuint *)ptr3;
552 register GLuint *p, px;
553 GLuint w = width;
554 switch (3 & (int)(ptr3 - (bgr_t*) ptr4)){
555 case 0:
556 break;
557 case 1:
558 px = *ptr4 & 0x00ffffff;
559 px |= pixel4[0] & 0xff000000;
560 *ptr4++ = px;
561 px = *ptr4 & 0xffff0000;
562 px |= pixel4[2] & 0x0000ffff;
563 *ptr4 = px;
564 if (0 == --w)
565 break;
566 case 2:
567 px = *ptr4 & 0x0000fffff;
568 px |= pixel4[1] & 0xffff0000;
569 *ptr4++ = px;
570 px = *ptr4 & 0xffffff00;
571 px |= pixel4[2] & 0x000000ff;
572 *ptr4 = px;
573 if (0 == --w)
574 break;
575 case 3:
576 px = *ptr4 & 0x000000ff;
577 px |= pixel4[2] & 0xffffff00;
578 *ptr4++ = px;
579 --w;
580 break;
581 }
582 while (w > 3){
583 p = pixel4;
584 *ptr4++ = *p++;
585 *ptr4++ = *p++;
586 *ptr4++ = *p++;
587 w -= 4;
588 }
589 switch (w) {
590 case 3:
591 p = pixel4;
592 *ptr4++ = *p++;
593 *ptr4++ = *p++;
594 px = *ptr4 & 0xffffff00;
595 px |= *p & 0xff;
596 *ptr4 = px;
597 break;
598 case 2:
599 p = pixel4;
600 *ptr4++ = *p++;
601 px = *ptr4 & 0xffff0000;
602 px |= *p & 0xffff;
603 *ptr4 = px;
604 break;
605 case 1:
606 px = *ptr4 & 0xff000000;
607 px |= pixel4[0] & 0xffffff;
608 *ptr4 = px;
609 break;
610 case 0:
611 break;
612 }
613 }
614 #endif
615 }
616 }
617 }
618
619
620 static void
621 clear_32bit_ximage( GLcontext *ctx, GLboolean all,
622 GLint x, GLint y, GLint width, GLint height )
623 {
624 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
625 register GLuint pixel = (GLuint) xmesa->clearpixel;
626 if (xmesa->swapbytes) {
627 pixel = ((pixel >> 24) & 0x000000ff)
628 | ((pixel >> 8) & 0x0000ff00)
629 | ((pixel << 8) & 0x00ff0000)
630 | ((pixel << 24) & 0xff000000);
631 }
632 if (all) {
633 register GLint n = xmesa->xm_draw_buffer->width * xmesa->xm_draw_buffer->height;
634 register GLuint *ptr4 = (GLuint *) xmesa->xm_draw_buffer->backimage->data;
635 if (pixel==0) {
636 MEMSET( ptr4, pixel, 4*n );
637 }
638 else {
639 do {
640 *ptr4++ = pixel;
641 n--;
642 } while (n!=0);
643 }
644 }
645 else {
646 register int i, j;
647 for (j=0;j<height;j++) {
648 register GLuint *ptr4 = PIXELADDR4( xmesa->xm_draw_buffer, x, y+j );
649 for (i=0;i<width;i++) {
650 *ptr4++ = pixel;
651 }
652 }
653 }
654 }
655
656
657 static void
658 clear_nbit_ximage( GLcontext *ctx, GLboolean all,
659 GLint x, GLint y, GLint width, GLint height )
660 {
661 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
662 XMesaImage *img = xmesa->xm_draw_buffer->backimage;
663 if (all) {
664 register int i, j;
665 width = xmesa->xm_draw_buffer->width;
666 height = xmesa->xm_draw_buffer->height;
667 for (j=0;j<height;j++) {
668 for (i=0;i<width;i++) {
669 XMesaPutPixel( img, i, j, xmesa->clearpixel );
670 }
671 }
672 }
673 else {
674 /* TODO: optimize this */
675 register int i, j;
676 y = FLIP(xmesa->xm_draw_buffer, y);
677 for (j=0;j<height;j++) {
678 for (i=0;i<width;i++) {
679 XMesaPutPixel( img, x+i, y-j, xmesa->clearpixel );
680 }
681 }
682 }
683 }
684
685
686
687 static void
688 clear_buffers( GLcontext *ctx, GLbitfield mask,
689 GLboolean all, GLint x, GLint y, GLint width, GLint height )
690 {
691 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
692 const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask;
693
694 if ((mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT)) &&
695 xmesa->xm_draw_buffer->mesa_buffer.UseSoftwareAlphaBuffers &&
696 ctx->Color.ColorMask[ACOMP]) {
697 _swrast_clear_alpha_buffers(ctx);
698 }
699
700 /* we can't handle color or index masking */
701 if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) {
702 if (mask & DD_FRONT_LEFT_BIT) {
703 ASSERT(xmesa->xm_draw_buffer->front_clear_func);
704 (*xmesa->xm_draw_buffer->front_clear_func)( ctx, all, x, y, width, height );
705 mask &= ~DD_FRONT_LEFT_BIT;
706 }
707 if (mask & DD_BACK_LEFT_BIT) {
708 ASSERT(xmesa->xm_draw_buffer->back_clear_func);
709 (*xmesa->xm_draw_buffer->back_clear_func)( ctx, all, x, y, width, height );
710 mask &= ~DD_BACK_LEFT_BIT;
711 }
712 }
713
714 if (mask)
715 _swrast_Clear( ctx, mask, all, x, y, width, height );
716 }
717
718
719 /*
720 * When we detect that the user has resized the window this function will
721 * get called. Here we'll reallocate the back buffer, depth buffer,
722 * stencil buffer etc. to match the new window size.
723 */
724 void
725 xmesa_resize_buffers( GLframebuffer *buffer )
726 {
727 int height = (int) buffer->Height;
728 /* We can do this cast because the first field in the XMesaBuffer
729 * struct is a GLframebuffer struct. If this weren't true, we'd
730 * need a pointer from the GLframebuffer to the XMesaBuffer.
731 */
732 XMesaBuffer xmBuffer = (XMesaBuffer) buffer;
733
734 xmBuffer->width = buffer->Width;
735 xmBuffer->height = buffer->Height;
736 xmesa_alloc_back_buffer( xmBuffer );
737
738 /* Needed by FLIP macro */
739 xmBuffer->bottom = height - 1;
740
741 if (xmBuffer->backimage) {
742 /* Needed by PIXELADDR1 macro */
743 xmBuffer->ximage_width1 = xmBuffer->backimage->bytes_per_line;
744 xmBuffer->ximage_origin1 = (GLubyte *) xmBuffer->backimage->data
745 + xmBuffer->ximage_width1 * (height-1);
746
747 /* Needed by PIXELADDR2 macro */
748 xmBuffer->ximage_width2 = xmBuffer->backimage->bytes_per_line / 2;
749 xmBuffer->ximage_origin2 = (GLushort *) xmBuffer->backimage->data
750 + xmBuffer->ximage_width2 * (height-1);
751
752 /* Needed by PIXELADDR3 macro */
753 xmBuffer->ximage_width3 = xmBuffer->backimage->bytes_per_line;
754 xmBuffer->ximage_origin3 = (GLubyte *) xmBuffer->backimage->data
755 + xmBuffer->ximage_width3 * (height-1);
756
757 /* Needed by PIXELADDR4 macro */
758 xmBuffer->ximage_width4 = xmBuffer->backimage->width;
759 xmBuffer->ximage_origin4 = (GLuint *) xmBuffer->backimage->data
760 + xmBuffer->ximage_width4 * (height-1);
761 }
762
763 _swrast_alloc_buffers( buffer );
764 }
765
766
767 #ifndef XFree86Server
768 /* XXX this was never tested in the Xserver environment */
769
770 /**
771 * This function implements glDrawPixels() with an XPutImage call when
772 * drawing to the front buffer (X Window drawable).
773 * The image format must be GL_BGRA to match the PF_8R8G8B pixel format.
774 */
775 static void
776 xmesa_DrawPixels_8R8G8B( GLcontext *ctx,
777 GLint x, GLint y, GLsizei width, GLsizei height,
778 GLenum format, GLenum type,
779 const struct gl_pixelstore_attrib *unpack,
780 const GLvoid *pixels )
781 {
782 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
783 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
784 XMesaDisplay *dpy = xmesa->xm_visual->display;
785 const XMesaDrawable buffer = xmesa->xm_draw_buffer->buffer;
786 const XMesaGC gc = xmesa->xm_draw_buffer->gc;
787
788 ASSERT(dpy);
789 ASSERT(gc);
790 ASSERT(xmesa->xm_visual->dithered_pf == PF_8R8G8B);
791 ASSERT(xmesa->xm_visual->undithered_pf == PF_8R8G8B);
792
793 if (buffer && /* buffer != 0 means it's a Window or Pixmap */
794 format == GL_BGRA &&
795 type == GL_UNSIGNED_BYTE &&
796 (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */
797 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
798 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
799 ctx->Pixel.ZoomY == 1.0) {
800 int dstX = x;
801 int dstY = y;
802 int w = width;
803 int h = height;
804 int srcX = unpack->SkipPixels;
805 int srcY = unpack->SkipRows;
806 int rowLength = unpack->RowLength ? unpack->RowLength : width;
807 if (_swrast_clip_pixelrect(ctx, &dstX, &dstY, &w, &h, &srcX, &srcY)) {
808 /* This is a little tricky since all coordinates up to now have
809 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom
810 * so we have to carefully compute the Y coordinates/addresses here.
811 */
812 XMesaImage ximage;
813 MEMSET(&ximage, 0, sizeof(XMesaImage));
814 ximage.width = width;
815 ximage.height = height;
816 ximage.format = ZPixmap;
817 ximage.data = (char *) pixels
818 + ((srcY + h - 1) * rowLength + srcX) * 4;
819 ximage.byte_order = LSBFirst;
820 ximage.bitmap_unit = 32;
821 ximage.bitmap_bit_order = LSBFirst;
822 ximage.bitmap_pad = 32;
823 ximage.depth = 24;
824 ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */
825 ximage.bits_per_pixel = 32;
826 /* it seems we don't need to set the ximage.red/green/blue_mask fields */
827 /* flip Y axis for dest position */
828 dstY = FLIP(xmesa->xm_draw_buffer, dstY) - h + 1;
829 XPutImage(dpy, buffer, gc, &ximage, 0, 0, dstX, dstY, w, h);
830 }
831 }
832 else {
833 /* software fallback */
834 _swrast_DrawPixels(ctx, x, y, width, height,
835 format, type, unpack, pixels);
836 }
837 }
838
839
840
841 /**
842 * This function implements glDrawPixels() with an XPutImage call when
843 * drawing to the front buffer (X Window drawable). The image format
844 * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to
845 * match the PF_5R6G5B pixel format.
846 */
847 static void
848 xmesa_DrawPixels_5R6G5B( GLcontext *ctx,
849 GLint x, GLint y, GLsizei width, GLsizei height,
850 GLenum format, GLenum type,
851 const struct gl_pixelstore_attrib *unpack,
852 const GLvoid *pixels )
853 {
854 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
855 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
856 XMesaDisplay *dpy = xmesa->xm_visual->display;
857 const XMesaDrawable buffer = xmesa->xm_draw_buffer->buffer;
858 const XMesaGC gc = xmesa->xm_draw_buffer->gc;
859
860 ASSERT(dpy);
861 ASSERT(gc);
862 ASSERT(xmesa->xm_visual->undithered_pf == PF_5R6G5B);
863
864 if (buffer && /* buffer != 0 means it's a Window or Pixmap */
865 format == GL_RGB &&
866 type == GL_UNSIGNED_SHORT_5_6_5 &&
867 !ctx->Color.DitherFlag && /* no dithering */
868 (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */
869 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
870 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
871 ctx->Pixel.ZoomY == 1.0) {
872 int dstX = x;
873 int dstY = y;
874 int w = width;
875 int h = height;
876 int srcX = unpack->SkipPixels;
877 int srcY = unpack->SkipRows;
878 int rowLength = unpack->RowLength ? unpack->RowLength : width;
879 if (_swrast_clip_pixelrect(ctx, &dstX, &dstY, &w, &h, &srcX, &srcY)) {
880 /* This is a little tricky since all coordinates up to now have
881 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom
882 * so we have to carefully compute the Y coordinates/addresses here.
883 */
884 XMesaImage ximage;
885 MEMSET(&ximage, 0, sizeof(XMesaImage));
886 ximage.width = width;
887 ximage.height = height;
888 ximage.format = ZPixmap;
889 ximage.data = (char *) pixels
890 + ((srcY + h - 1) * rowLength + srcX) * 2;
891 ximage.byte_order = LSBFirst;
892 ximage.bitmap_unit = 16;
893 ximage.bitmap_bit_order = LSBFirst;
894 ximage.bitmap_pad = 16;
895 ximage.depth = 16;
896 ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */
897 ximage.bits_per_pixel = 16;
898 /* it seems we don't need to set the ximage.red/green/blue_mask fields */
899 /* flip Y axis for dest position */
900 dstY = FLIP(xmesa->xm_draw_buffer, dstY) - h + 1;
901 XPutImage(dpy, buffer, gc, &ximage, 0, 0, dstX, dstY, w, h);
902 }
903 }
904 else {
905 /* software fallback */
906 _swrast_DrawPixels(ctx, x, y, width, height,
907 format, type, unpack, pixels);
908 }
909 }
910
911
912
913 /**
914 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
915 * for the color buffer. Don't support zooming, pixel transfer, etc.
916 * We do support copying from one window to another, ala glXMakeCurrentRead.
917 */
918 static void
919 xmesa_CopyPixels( GLcontext *ctx,
920 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
921 GLint destx, GLint desty, GLenum type )
922 {
923 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
924 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
925 XMesaDisplay *dpy = xmesa->xm_visual->display;
926 const XMesaDrawable drawBuffer = xmesa->xm_draw_buffer->buffer;
927 const XMesaDrawable readBuffer = xmesa->xm_read_buffer->buffer;
928 const XMesaGC gc = xmesa->xm_draw_buffer->gc;
929
930 ASSERT(dpy);
931 ASSERT(gc);
932
933 if (ctx->Color.DrawBuffer == GL_FRONT &&
934 ctx->Pixel.ReadBuffer == GL_FRONT &&
935 drawBuffer && /* buffer != 0 means it's a Window or Pixmap */
936 readBuffer &&
937 type == GL_COLOR &&
938 (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */
939 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
940 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
941 ctx->Pixel.ZoomY == 1.0) {
942 /* Note: we don't do any special clipping work here. We could,
943 * but X will do it for us.
944 */
945 srcy = FLIP(xmesa->xm_read_buffer, srcy) - height + 1;
946 desty = FLIP(xmesa->xm_draw_buffer, desty) - height + 1;
947 XCopyArea(dpy, readBuffer, drawBuffer, gc,
948 srcx, srcy, width, height, destx, desty);
949 }
950 else {
951 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type );
952 }
953 }
954 #endif /* XFree86Server */
955
956
957
958 /*
959 * Every driver should implement a GetString function in order to
960 * return a meaningful GL_RENDERER string.
961 */
962 static const GLubyte *
963 get_string( GLcontext *ctx, GLenum name )
964 {
965 (void) ctx;
966 switch (name) {
967 case GL_RENDERER:
968 #ifdef XFree86Server
969 return (const GLubyte *) "Mesa GLX Indirect";
970 #else
971 return (const GLubyte *) "Mesa X11";
972 #endif
973 case GL_VENDOR:
974 #ifdef XFree86Server
975 return (const GLubyte *) "Mesa project: www.mesa3d.org";
976 #else
977 return NULL;
978 #endif
979 default:
980 return NULL;
981 }
982 }
983
984
985 /*
986 * We implement the glEnable function only because we care about
987 * dither enable/disable.
988 */
989 static void
990 enable( GLcontext *ctx, GLenum pname, GLboolean state )
991 {
992 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
993
994 switch (pname) {
995 case GL_DITHER:
996 if (state)
997 xmesa->pixelformat = xmesa->xm_visual->dithered_pf;
998 else
999 xmesa->pixelformat = xmesa->xm_visual->undithered_pf;
1000 break;
1001 default:
1002 ; /* silence compiler warning */
1003 }
1004 }
1005
1006
1007 void xmesa_update_state( GLcontext *ctx, GLuint new_state )
1008 {
1009 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
1010
1011 /* Propogate statechange information to swrast and swrast_setup
1012 * modules. The X11 driver has no internal GL-dependent state.
1013 */
1014 _swrast_InvalidateState( ctx, new_state );
1015 _ac_InvalidateState( ctx, new_state );
1016 _tnl_InvalidateState( ctx, new_state );
1017 _swsetup_InvalidateState( ctx, new_state );
1018
1019
1020 /* setup pointers to front and back buffer clear functions */
1021 xmesa->xm_draw_buffer->front_clear_func = clear_front_pixmap;
1022 if (xmesa->xm_draw_buffer->backpixmap != XIMAGE) {
1023 xmesa->xm_draw_buffer->back_clear_func = clear_back_pixmap;
1024 }
1025 else if (sizeof(GLushort)!=2 || sizeof(GLuint)!=4) {
1026 xmesa->xm_draw_buffer->back_clear_func = clear_nbit_ximage;
1027 }
1028 else switch (xmesa->xm_visual->BitsPerPixel) {
1029 case 8:
1030 if (xmesa->xm_visual->hpcr_clear_flag) {
1031 xmesa->xm_draw_buffer->back_clear_func = clear_HPCR_ximage;
1032 }
1033 else {
1034 xmesa->xm_draw_buffer->back_clear_func = clear_8bit_ximage;
1035 }
1036 break;
1037 case 16:
1038 xmesa->xm_draw_buffer->back_clear_func = clear_16bit_ximage;
1039 break;
1040 case 24:
1041 xmesa->xm_draw_buffer->back_clear_func = clear_24bit_ximage;
1042 break;
1043 case 32:
1044 xmesa->xm_draw_buffer->back_clear_func = clear_32bit_ximage;
1045 break;
1046 default:
1047 xmesa->xm_draw_buffer->back_clear_func = clear_nbit_ximage;
1048 break;
1049 }
1050
1051 xmesa_update_span_funcs(ctx);
1052 }
1053
1054
1055
1056 /**
1057 * Called via ctx->Driver.TestProxyTeximage(). Normally, we'd just use
1058 * the _mesa_test_proxy_teximage() fallback function, but we're going to
1059 * special-case the 3D texture case to allow textures up to 512x512x32
1060 * texels.
1061 */
1062 static GLboolean
1063 test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
1064 GLint internalFormat, GLenum format, GLenum type,
1065 GLint width, GLint height, GLint depth, GLint border)
1066 {
1067 if (target == GL_PROXY_TEXTURE_3D) {
1068 /* special case for 3D textures */
1069 if (width * height * depth > 512 * 512 * 64 ||
1070 width < 2 * border ||
1071 (!ctx->Extensions.ARB_texture_non_power_of_two &&
1072 _mesa_bitcount(width - 2 * border) != 1) ||
1073 height < 2 * border ||
1074 (!ctx->Extensions.ARB_texture_non_power_of_two &&
1075 _mesa_bitcount(height - 2 * border) != 1) ||
1076 depth < 2 * border ||
1077 (!ctx->Extensions.ARB_texture_non_power_of_two &&
1078 _mesa_bitcount(depth - 2 * border) != 1)) {
1079 /* Bad size, or too many texels */
1080 return GL_FALSE;
1081 }
1082 return GL_TRUE;
1083 }
1084 else {
1085 /* use the fallback routine for 1D, 2D, cube and rect targets */
1086 return _mesa_test_proxy_teximage(ctx, target, level, internalFormat,
1087 format, type, width, height, depth,
1088 border);
1089 }
1090 }
1091
1092
1093
1094
1095 /* Setup pointers and other driver state that is constant for the life
1096 * of a context.
1097 */
1098 void xmesa_init_pointers( GLcontext *ctx )
1099 {
1100 TNLcontext *tnl;
1101 struct swrast_device_driver *dd = _swrast_GetDeviceDriverReference( ctx );
1102 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
1103
1104 /* Plug in our driver-specific functions here */
1105 ctx->Driver.GetString = get_string;
1106 ctx->Driver.GetBufferSize = get_buffer_size;
1107 ctx->Driver.Flush = finish_or_flush;
1108 ctx->Driver.Finish = finish_or_flush;
1109 ctx->Driver.ClearIndex = clear_index;
1110 ctx->Driver.ClearColor = clear_color;
1111 ctx->Driver.IndexMask = index_mask;
1112 ctx->Driver.ColorMask = color_mask;
1113 ctx->Driver.Enable = enable;
1114
1115 /* Software rasterizer pixel paths:
1116 */
1117 ctx->Driver.Accum = _swrast_Accum;
1118 ctx->Driver.Bitmap = _swrast_Bitmap;
1119 ctx->Driver.Clear = clear_buffers;
1120 ctx->Driver.ResizeBuffers = xmesa_resize_buffers;
1121 #ifdef XFree86Server
1122 ctx->Driver.DrawPixels = _swrast_DrawPixels;
1123 ctx->Driver.CopyPixels = _swrast_CopyPixels;
1124 #else
1125 ctx->Driver.CopyPixels = /*_swrast_CopyPixels;*/xmesa_CopyPixels;
1126 if (xmesa->xm_visual->undithered_pf == PF_8R8G8B &&
1127 xmesa->xm_visual->dithered_pf == PF_8R8G8B) {
1128 ctx->Driver.DrawPixels = xmesa_DrawPixels_8R8G8B;
1129 }
1130 else if (xmesa->xm_visual->undithered_pf == PF_5R6G5B) {
1131 ctx->Driver.DrawPixels = xmesa_DrawPixels_5R6G5B;
1132 }
1133 else {
1134 ctx->Driver.DrawPixels = _swrast_DrawPixels;
1135 }
1136 #endif
1137 ctx->Driver.ReadPixels = _swrast_ReadPixels;
1138 ctx->Driver.DrawBuffer = _swrast_DrawBuffer;
1139
1140 /* Software texture functions:
1141 */
1142 ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format;
1143 ctx->Driver.TexImage1D = _mesa_store_teximage1d;
1144 ctx->Driver.TexImage2D = _mesa_store_teximage2d;
1145 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
1146 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
1147 ctx->Driver.TexSubImage2D = _mesa_store_texsubimage2d;
1148 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
1149 ctx->Driver.TestProxyTexImage = test_proxy_teximage;
1150
1151 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
1152 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
1153 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
1154 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
1155 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
1156
1157 ctx->Driver.CompressedTexImage1D = _mesa_store_compressed_teximage1d;
1158 ctx->Driver.CompressedTexImage2D = _mesa_store_compressed_teximage2d;
1159 ctx->Driver.CompressedTexImage3D = _mesa_store_compressed_teximage3d;
1160 ctx->Driver.CompressedTexSubImage1D = _mesa_store_compressed_texsubimage1d;
1161 ctx->Driver.CompressedTexSubImage2D = _mesa_store_compressed_texsubimage2d;
1162 ctx->Driver.CompressedTexSubImage3D = _mesa_store_compressed_texsubimage3d;
1163
1164 /* Swrast hooks for imaging extensions:
1165 */
1166 ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
1167 ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
1168 ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
1169 ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
1170
1171 /* Initialize the TNL driver interface:
1172 */
1173 tnl = TNL_CONTEXT(ctx);
1174 tnl->Driver.RunPipeline = _tnl_run_pipeline;
1175
1176 dd->SetBuffer = set_buffer;
1177
1178 /* Install swsetup for tnl->Driver.Render.*:
1179 */
1180 _swsetup_Wakeup(ctx);
1181
1182 (void) DitherValues; /* silenced unused var warning */
1183 }
1184
1185
1186
1187
1188
1189 #define XMESA_NEW_POINT (_NEW_POINT | \
1190 _NEW_RENDERMODE | \
1191 _SWRAST_NEW_RASTERMASK)
1192
1193 #define XMESA_NEW_LINE (_NEW_LINE | \
1194 _NEW_TEXTURE | \
1195 _NEW_LIGHT | \
1196 _NEW_DEPTH | \
1197 _NEW_RENDERMODE | \
1198 _SWRAST_NEW_RASTERMASK)
1199
1200 #define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \
1201 _NEW_TEXTURE | \
1202 _NEW_LIGHT | \
1203 _NEW_DEPTH | \
1204 _NEW_RENDERMODE | \
1205 _SWRAST_NEW_RASTERMASK)
1206
1207
1208 /* Extend the software rasterizer with our line/point/triangle
1209 * functions.
1210 */
1211 void xmesa_register_swrast_functions( GLcontext *ctx )
1212 {
1213 SWcontext *swrast = SWRAST_CONTEXT( ctx );
1214
1215 swrast->choose_point = xmesa_choose_point;
1216 swrast->choose_line = xmesa_choose_line;
1217 swrast->choose_triangle = xmesa_choose_triangle;
1218
1219 swrast->invalidate_point |= XMESA_NEW_POINT;
1220 swrast->invalidate_line |= XMESA_NEW_LINE;
1221 swrast->invalidate_triangle |= XMESA_NEW_TRIANGLE;
1222 }