osmesa.c revision bc69de5f21ebb4d6e1c65bf5652d17a9fc87dda7
1/* $Id: osmesa.c,v 1.54 2001/05/10 12:22:32 keithw Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28/* 29 * Off-Screen Mesa rendering / Rendering into client memory space 30 * 31 * Note on thread safety: this driver is thread safe. All 32 * functions are reentrant. The notion of current context is 33 * managed by the core _mesa_make_current() and _mesa_get_current_context() 34 * functions. Those functions are thread-safe. 35 */ 36 37 38#include "glheader.h" 39#include "GL/osmesa.h" 40#include "context.h" 41#include "colormac.h" 42#include "depth.h" 43#include "extensions.h" 44#include "macros.h" 45#include "matrix.h" 46#include "mem.h" 47#include "mmath.h" 48#include "mtypes.h" 49#include "texformat.h" 50#include "texstore.h" 51#include "array_cache/acache.h" 52#include "swrast/swrast.h" 53#include "swrast_setup/swrast_setup.h" 54#include "swrast/s_context.h" 55#include "swrast/s_depth.h" 56#include "swrast/s_lines.h" 57#include "swrast/s_triangle.h" 58#include "tnl/tnl.h" 59#include "tnl/t_context.h" 60#include "tnl/t_pipeline.h" 61 62 63 64/* 65 * This is the OS/Mesa context struct. 66 * Notice how it includes a GLcontext. By doing this we're mimicking 67 * C++ inheritance/derivation. 68 * Later, we can cast a GLcontext pointer into an OSMesaContext pointer 69 * or vice versa. 70 */ 71struct osmesa_context { 72 GLcontext gl_ctx; /* The core GL/Mesa context */ 73 GLvisual *gl_visual; /* Describes the buffers */ 74 GLframebuffer *gl_buffer; /* Depth, stencil, accum, etc buffers */ 75 GLenum format; /* either GL_RGBA or GL_COLOR_INDEX */ 76 void *buffer; /* the image buffer */ 77 GLint width, height; /* size of image buffer */ 78 GLint rowlength; /* number of pixels per row */ 79 GLint userRowLength; /* user-specified number of pixels per row */ 80 GLint rshift, gshift; /* bit shifts for RGBA formats */ 81 GLint bshift, ashift; 82 GLint rInd, gInd, bInd, aInd;/* index offsets for RGBA formats */ 83 GLchan *rowaddr[MAX_HEIGHT]; /* address of first pixel in each image row */ 84 GLboolean yup; /* TRUE -> Y increases upward */ 85 /* FALSE -> Y increases downward */ 86}; 87 88 89 90/* A forward declaration: */ 91static void osmesa_update_state( GLcontext *ctx, GLuint newstate ); 92static void osmesa_register_swrast_functions( GLcontext *ctx ); 93 94 95 96#define OSMESA_CONTEXT(ctx) ((OSMesaContext) (ctx->DriverCtx)) 97 98 99 100/**********************************************************************/ 101/***** Public Functions *****/ 102/**********************************************************************/ 103 104 105/* 106 * Create an Off-Screen Mesa rendering context. The only attribute needed is 107 * an RGBA vs Color-Index mode flag. 108 * 109 * Input: format - either GL_RGBA or GL_COLOR_INDEX 110 * sharelist - specifies another OSMesaContext with which to share 111 * display lists. NULL indicates no sharing. 112 * Return: an OSMesaContext or 0 if error 113 */ 114OSMesaContext GLAPIENTRY 115OSMesaCreateContext( GLenum format, OSMesaContext sharelist ) 116{ 117 return OSMesaCreateContextExt(format, DEFAULT_SOFTWARE_DEPTH_BITS, 118 8, 16, sharelist); 119} 120 121 122 123/* 124 * New in Mesa 3.5 125 * 126 * Create context and specify size of ancillary buffers. 127 */ 128OSMesaContext GLAPIENTRY 129OSMesaCreateContextExt( GLenum format, GLint depthBits, GLint stencilBits, 130 GLint accumBits, OSMesaContext sharelist ) 131{ 132 OSMesaContext osmesa; 133 GLint rshift, gshift, bshift, ashift; 134 GLint rind, gind, bind, aind; 135 GLint indexBits = 0, redBits = 0, greenBits = 0, blueBits = 0, alphaBits =0; 136 GLboolean rgbmode; 137 GLboolean swalpha; 138 const GLuint i4 = 1; 139 const GLubyte *i1 = (GLubyte *) &i4; 140 const GLint little_endian = *i1; 141 142 swalpha = GL_FALSE; 143 rind = gind = bind = aind = 0; 144 if (format==OSMESA_COLOR_INDEX) { 145 indexBits = 8; 146 rshift = gshift = bshift = ashift = 0; 147 rgbmode = GL_FALSE; 148 } 149 else if (format==OSMESA_RGBA) { 150 indexBits = 0; 151 redBits = CHAN_BITS; 152 greenBits = CHAN_BITS; 153 blueBits = CHAN_BITS; 154 alphaBits = CHAN_BITS; 155 rind = 0; 156 gind = 1; 157 bind = 2; 158 aind = 3; 159 if (little_endian) { 160 rshift = 0; 161 gshift = 8; 162 bshift = 16; 163 ashift = 24; 164 } 165 else { 166 rshift = 24; 167 gshift = 16; 168 bshift = 8; 169 ashift = 0; 170 } 171 rgbmode = GL_TRUE; 172 } 173 else if (format==OSMESA_BGRA) { 174 indexBits = 0; 175 redBits = CHAN_BITS; 176 greenBits = CHAN_BITS; 177 blueBits = CHAN_BITS; 178 alphaBits = CHAN_BITS; 179 rind = 2; 180 gind = 1; 181 bind = 0; 182 aind = 3; 183 if (little_endian) { 184 ashift = 0; 185 rshift = 8; 186 gshift = 16; 187 bshift = 24; 188 } 189 else { 190 bshift = 24; 191 gshift = 16; 192 rshift = 8; 193 ashift = 0; 194 } 195 rgbmode = GL_TRUE; 196 } 197 else if (format==OSMESA_ARGB) { 198 indexBits = 0; 199 redBits = CHAN_BITS; 200 greenBits = CHAN_BITS; 201 blueBits = CHAN_BITS; 202 alphaBits = CHAN_BITS; 203 rind = 1; 204 gind = 2; 205 bind = 3; 206 aind = 0; 207 if (little_endian) { 208 bshift = 0; 209 gshift = 8; 210 rshift = 16; 211 ashift = 24; 212 } 213 else { 214 ashift = 24; 215 rshift = 16; 216 gshift = 8; 217 bshift = 0; 218 } 219 rgbmode = GL_TRUE; 220 } 221 else if (format==OSMESA_RGB) { 222 indexBits = 0; 223 redBits = CHAN_BITS; 224 greenBits = CHAN_BITS; 225 blueBits = CHAN_BITS; 226 alphaBits = 0; 227 bshift = 0; 228 gshift = 8; 229 rshift = 16; 230 ashift = 24; 231 rind = 0; 232 gind = 1; 233 bind = 2; 234 rgbmode = GL_TRUE; 235 swalpha = GL_TRUE; 236 } 237 else if (format==OSMESA_BGR) { 238 indexBits = 0; 239 redBits = CHAN_BITS; 240 greenBits = CHAN_BITS; 241 blueBits = CHAN_BITS; 242 alphaBits = 0; 243 bshift = 0; 244 gshift = 8; 245 rshift = 16; 246 ashift = 24; 247 rind = 2; 248 gind = 1; 249 bind = 0; 250 rgbmode = GL_TRUE; 251 swalpha = GL_TRUE; 252 } 253 else { 254 return NULL; 255 } 256 257 258 osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context); 259 if (osmesa) { 260 osmesa->gl_visual = _mesa_create_visual( rgbmode, 261 GL_FALSE, /* double buffer */ 262 GL_FALSE, /* stereo */ 263 redBits, 264 greenBits, 265 blueBits, 266 alphaBits, 267 indexBits, 268 depthBits, 269 stencilBits, 270 accumBits, 271 accumBits, 272 accumBits, 273 alphaBits ? accumBits : 0, 274 1 /* num samples */ 275 ); 276 if (!osmesa->gl_visual) { 277 FREE(osmesa); 278 return NULL; 279 } 280 281 if (!_mesa_initialize_context(&osmesa->gl_ctx, 282 osmesa->gl_visual, 283 sharelist ? &sharelist->gl_ctx 284 : (GLcontext *) NULL, 285 (void *) osmesa, GL_TRUE )) { 286 _mesa_destroy_visual( osmesa->gl_visual ); 287 FREE(osmesa); 288 return NULL; 289 } 290 291 _mesa_enable_sw_extensions(&(osmesa->gl_ctx)); 292 293 osmesa->gl_buffer = _mesa_create_framebuffer( osmesa->gl_visual, 294 osmesa->gl_visual->depthBits > 0, 295 osmesa->gl_visual->stencilBits > 0, 296 osmesa->gl_visual->accumRedBits > 0, 297 osmesa->gl_visual->alphaBits > 0 ); 298 299 if (!osmesa->gl_buffer) { 300 _mesa_destroy_visual( osmesa->gl_visual ); 301 _mesa_free_context_data( &osmesa->gl_ctx ); 302 FREE(osmesa); 303 return NULL; 304 } 305 osmesa->format = format; 306 osmesa->buffer = NULL; 307 osmesa->width = 0; 308 osmesa->height = 0; 309 osmesa->userRowLength = 0; 310 osmesa->rowlength = 0; 311 osmesa->yup = GL_TRUE; 312 osmesa->rshift = rshift; 313 osmesa->gshift = gshift; 314 osmesa->bshift = bshift; 315 osmesa->ashift = ashift; 316 osmesa->rInd = rind; 317 osmesa->gInd = gind; 318 osmesa->bInd = bind; 319 osmesa->aInd = aind; 320 321 322 /* Initialize the software rasterizer and helper modules. 323 */ 324 { 325 GLcontext *ctx = &osmesa->gl_ctx; 326 327 _swrast_CreateContext( ctx ); 328 _ac_CreateContext( ctx ); 329 _tnl_CreateContext( ctx ); 330 _swsetup_CreateContext( ctx ); 331 332 osmesa_register_swrast_functions( ctx ); 333 } 334 } 335 return osmesa; 336} 337 338 339 340 341/* 342 * Destroy an Off-Screen Mesa rendering context. 343 * 344 * Input: ctx - the context to destroy 345 */ 346void GLAPIENTRY OSMesaDestroyContext( OSMesaContext ctx ) 347{ 348 if (ctx) { 349 _swsetup_DestroyContext( &ctx->gl_ctx ); 350 _tnl_DestroyContext( &ctx->gl_ctx ); 351 _ac_DestroyContext( &ctx->gl_ctx ); 352 _swrast_DestroyContext( &ctx->gl_ctx ); 353 354 _mesa_destroy_visual( ctx->gl_visual ); 355 _mesa_destroy_framebuffer( ctx->gl_buffer ); 356 _mesa_free_context_data( &ctx->gl_ctx ); 357 FREE( ctx ); 358 } 359} 360 361 362 363/* 364 * Recompute the values of the context's rowaddr array. 365 */ 366static void compute_row_addresses( OSMesaContext ctx ) 367{ 368 GLint bytesPerPixel, bytesPerRow, i; 369 GLubyte *origin = (GLubyte *) ctx->buffer; 370 371 if (ctx->format == OSMESA_COLOR_INDEX) { 372 /* CI mode */ 373 bytesPerPixel = 1 * sizeof(GLchan); 374 } 375 else if ((ctx->format == OSMESA_RGB) || (ctx->format == OSMESA_BGR)) { 376 /* RGB mode */ 377 bytesPerPixel = 3 * sizeof(GLchan); 378 } 379 else { 380 /* RGBA mode */ 381 bytesPerPixel = 4 * sizeof(GLchan); 382 } 383 384 bytesPerRow = ctx->rowlength * bytesPerPixel; 385 386 if (ctx->yup) { 387 /* Y=0 is bottom line of window */ 388 for (i = 0; i < MAX_HEIGHT; i++) { 389 ctx->rowaddr[i] = (GLchan *) ((GLubyte *) origin + i * bytesPerRow); 390 } 391 } 392 else { 393 /* Y=0 is top line of window */ 394 for (i = 0; i < MAX_HEIGHT; i++) { 395 GLint j = ctx->height - i - 1; 396 ctx->rowaddr[i] = (GLchan *) ((GLubyte *) origin + j * bytesPerRow); 397 } 398 } 399} 400 401 402/* 403 * Bind an OSMesaContext to an image buffer. The image buffer is just a 404 * block of memory which the client provides. Its size must be at least 405 * as large as width*height*sizeof(type). Its address should be a multiple 406 * of 4 if using RGBA mode. 407 * 408 * Image data is stored in the order of glDrawPixels: row-major order 409 * with the lower-left image pixel stored in the first array position 410 * (ie. bottom-to-top). 411 * 412 * Since the only type initially supported is GL_UNSIGNED_BYTE, if the 413 * context is in RGBA mode, each pixel will be stored as a 4-byte RGBA 414 * value. If the context is in color indexed mode, each pixel will be 415 * stored as a 1-byte value. 416 * 417 * If the context's viewport hasn't been initialized yet, it will now be 418 * initialized to (0,0,width,height). 419 * 420 * Input: ctx - the rendering context 421 * buffer - the image buffer memory 422 * type - data type for pixel components, only GL_UNSIGNED_BYTE 423 * supported now 424 * width, height - size of image buffer in pixels, at least 1 425 * Return: GL_TRUE if success, GL_FALSE if error because of invalid ctx, 426 * invalid buffer address, type!=GL_UNSIGNED_BYTE, width<1, height<1, 427 * width>internal limit or height>internal limit. 428 */ 429GLboolean GLAPIENTRY 430OSMesaMakeCurrent( OSMesaContext ctx, void *buffer, GLenum type, 431 GLsizei width, GLsizei height ) 432{ 433 if (!ctx || !buffer || type != CHAN_TYPE || 434 width < 1 || height < 1 || 435 width > MAX_WIDTH || height > MAX_HEIGHT) { 436 return GL_FALSE; 437 } 438 439 osmesa_update_state( &ctx->gl_ctx, 0 ); 440 _mesa_make_current( &ctx->gl_ctx, ctx->gl_buffer ); 441 442 ctx->buffer = buffer; 443 ctx->width = width; 444 ctx->height = height; 445 if (ctx->userRowLength) 446 ctx->rowlength = ctx->userRowLength; 447 else 448 ctx->rowlength = width; 449 450 compute_row_addresses( ctx ); 451 452 /* init viewport */ 453 if (ctx->gl_ctx.Viewport.Width==0) { 454 /* initialize viewport and scissor box to buffer size */ 455 _mesa_Viewport( 0, 0, width, height ); 456 ctx->gl_ctx.Scissor.Width = width; 457 ctx->gl_ctx.Scissor.Height = height; 458 } 459 460 return GL_TRUE; 461} 462 463 464 465OSMesaContext GLAPIENTRY OSMesaGetCurrentContext( void ) 466{ 467 GLcontext *ctx = _mesa_get_current_context(); 468 if (ctx) 469 return (OSMesaContext) ctx; 470 else 471 return NULL; 472} 473 474 475 476void GLAPIENTRY OSMesaPixelStore( GLint pname, GLint value ) 477{ 478 OSMesaContext ctx = OSMesaGetCurrentContext(); 479 480 switch (pname) { 481 case OSMESA_ROW_LENGTH: 482 if (value<0) { 483 _mesa_error( &ctx->gl_ctx, GL_INVALID_VALUE, 484 "OSMesaPixelStore(value)" ); 485 return; 486 } 487 ctx->userRowLength = value; 488 ctx->rowlength = value; 489 break; 490 case OSMESA_Y_UP: 491 ctx->yup = value ? GL_TRUE : GL_FALSE; 492 break; 493 default: 494 _mesa_error( &ctx->gl_ctx, GL_INVALID_ENUM, "OSMesaPixelStore(pname)" ); 495 return; 496 } 497 498 compute_row_addresses( ctx ); 499} 500 501 502void GLAPIENTRY OSMesaGetIntegerv( GLint pname, GLint *value ) 503{ 504 OSMesaContext ctx = OSMesaGetCurrentContext(); 505 506 switch (pname) { 507 case OSMESA_WIDTH: 508 *value = ctx->width; 509 return; 510 case OSMESA_HEIGHT: 511 *value = ctx->height; 512 return; 513 case OSMESA_FORMAT: 514 *value = ctx->format; 515 return; 516 case OSMESA_TYPE: 517 *value = CHAN_TYPE; 518 return; 519 case OSMESA_ROW_LENGTH: 520 *value = ctx->rowlength; 521 return; 522 case OSMESA_Y_UP: 523 *value = ctx->yup; 524 return; 525 default: 526 _mesa_error(&ctx->gl_ctx, GL_INVALID_ENUM, "OSMesaGetIntergerv(pname)"); 527 return; 528 } 529} 530 531/* 532 * Return the depth buffer associated with an OSMesa context. 533 * Input: c - the OSMesa context 534 * Output: width, height - size of buffer in pixels 535 * bytesPerValue - bytes per depth value (2 or 4) 536 * buffer - pointer to depth buffer values 537 * Return: GL_TRUE or GL_FALSE to indicate success or failure. 538 */ 539GLboolean GLAPIENTRY 540OSMesaGetDepthBuffer( OSMesaContext c, GLint *width, GLint *height, 541 GLint *bytesPerValue, void **buffer ) 542{ 543 if ((!c->gl_buffer) || (!c->gl_buffer->DepthBuffer)) { 544 *width = 0; 545 *height = 0; 546 *bytesPerValue = 0; 547 *buffer = 0; 548 return GL_FALSE; 549 } 550 else { 551 *width = c->gl_buffer->Width; 552 *height = c->gl_buffer->Height; 553 if (c->gl_visual->depthBits <= 16) 554 *bytesPerValue = sizeof(GLushort); 555 else 556 *bytesPerValue = sizeof(GLuint); 557 *buffer = c->gl_buffer->DepthBuffer; 558 return GL_TRUE; 559 } 560} 561 562/* 563 * Return the color buffer associated with an OSMesa context. 564 * Input: c - the OSMesa context 565 * Output: width, height - size of buffer in pixels 566 * format - the pixel format (OSMESA_FORMAT) 567 * buffer - pointer to color buffer values 568 * Return: GL_TRUE or GL_FALSE to indicate success or failure. 569 */ 570GLboolean GLAPIENTRY 571OSMesaGetColorBuffer( OSMesaContext c, GLint *width, 572 GLint *height, GLint *format, void **buffer ) 573{ 574 if (!c->buffer) { 575 *width = 0; 576 *height = 0; 577 *format = 0; 578 *buffer = 0; 579 return GL_FALSE; 580 } 581 else { 582 *width = c->width; 583 *height = c->height; 584 *format = c->format; 585 *buffer = c->buffer; 586 return GL_TRUE; 587 } 588} 589 590/**********************************************************************/ 591/*** Device Driver Functions ***/ 592/**********************************************************************/ 593 594 595/* 596 * Useful macros: 597 */ 598 599#define PACK_RGBA(DST, R, G, B, A) \ 600do { \ 601 (DST)[osmesa->rInd] = R; \ 602 (DST)[osmesa->gInd] = G; \ 603 (DST)[osmesa->bInd] = B; \ 604 (DST)[osmesa->aInd] = A; \ 605} while (0) 606 607#define PACK_RGB(DST, R, G, B) \ 608do { \ 609 (DST)[0] = R; \ 610 (DST)[1] = G; \ 611 (DST)[2] = B; \ 612} while (0) 613 614#define PACK_BGR(DST, R, G, B) \ 615do { \ 616 (DST)[0] = B; \ 617 (DST)[1] = G; \ 618 (DST)[2] = R; \ 619} while (0) 620 621 622#define UNPACK_RED(P) ( (P)[osmesa->rInd] ) 623#define UNPACK_GREEN(P) ( (P)[osmesa->gInd] ) 624#define UNPACK_BLUE(P) ( (P)[osmesa->bInd] ) 625#define UNPACK_ALPHA(P) ( (P)[osmesa->aInd] ) 626 627 628#define PIXELADDR1(X,Y) (osmesa->rowaddr[Y] + (X)) 629#define PIXELADDR3(X,Y) (osmesa->rowaddr[Y] + 3 * (X)) 630#define PIXELADDR4(X,Y) (osmesa->rowaddr[Y] + 4 * (X)) 631 632 633 634static GLboolean set_draw_buffer( GLcontext *ctx, GLenum mode ) 635{ 636 (void) ctx; 637 if (mode==GL_FRONT_LEFT) { 638 return GL_TRUE; 639 } 640 else { 641 return GL_FALSE; 642 } 643} 644 645 646static void set_read_buffer( GLcontext *ctx, GLframebuffer *buffer, GLenum mode ) 647{ 648 /* separate read buffer not supported */ 649 ASSERT(buffer == ctx->DrawBuffer); 650 ASSERT(mode == GL_FRONT_LEFT); 651} 652 653 654static void clear( GLcontext *ctx, GLbitfield mask, GLboolean all, 655 GLint x, GLint y, GLint width, GLint height ) 656{ 657 OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 658 const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask; 659 660 /* sanity check - we only have a front-left buffer */ 661 ASSERT((mask & (DD_FRONT_RIGHT_BIT | DD_BACK_LEFT_BIT | DD_BACK_RIGHT_BIT)) == 0); 662 if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) { 663 if (mask & DD_FRONT_LEFT_BIT) { 664 if (osmesa->format == OSMESA_COLOR_INDEX) { 665 if (all) { 666 /* Clear whole CI buffer */ 667#if CHAN_TYPE == GL_UNSIGNED_BYTE 668 MEMSET(osmesa->buffer, ctx->Color.ClearIndex, 669 osmesa->rowlength * osmesa->height); 670#else 671 const GLint n = osmesa->rowlength * osmesa->height; 672 GLchan *buffer = (GLchan *) osmesa->buffer; 673 GLint i; 674 for (i = 0; i < n; i ++) { 675 buffer[i] = ctx->Color.ClearIndex; 676 } 677#endif 678 } 679 else { 680 /* Clear part of CI buffer */ 681 const GLchan clearIndex = (GLchan) ctx->Color.ClearIndex; 682 GLint i, j; 683 for (i = 0; i < height; i++) { 684 GLchan *ptr1 = PIXELADDR1(x, (y + i)); 685 for (j = 0; j < width; j++) { 686 *ptr1++ = clearIndex; 687 } 688 } 689 } 690 } 691 else if (osmesa->format == OSMESA_RGB) { 692 const GLchan r = ctx->Color.ClearColor[0]; 693 const GLchan g = ctx->Color.ClearColor[1]; 694 const GLchan b = ctx->Color.ClearColor[2]; 695 if (all) { 696 /* Clear whole RGB buffer */ 697 GLuint n = osmesa->rowlength * osmesa->height; 698 GLchan *ptr3 = (GLchan *) osmesa->buffer; 699 GLuint i; 700 for (i = 0; i < n; i++) { 701 PACK_RGB(ptr3, r, g, b); 702 ptr3 += 3; 703 } 704 } 705 else { 706 /* Clear part of RGB buffer */ 707 GLint i, j; 708 for (i = 0; i < height; i++) { 709 GLchan *ptr3 = PIXELADDR3(x, (y + i)); 710 for (j = 0; j < width; j++) { 711 PACK_RGB(ptr3, r, g, b); 712 ptr3 += 3; 713 } 714 } 715 } 716 } 717 else if (osmesa->format == OSMESA_BGR) { 718 const GLchan r = ctx->Color.ClearColor[0]; 719 const GLchan g = ctx->Color.ClearColor[1]; 720 const GLchan b = ctx->Color.ClearColor[2]; 721 if (all) { 722 /* Clear whole RGB buffer */ 723 const GLint n = osmesa->rowlength * osmesa->height; 724 GLchan *ptr3 = (GLchan *) osmesa->buffer; 725 GLint i; 726 for (i = 0; i < n; i++) { 727 PACK_BGR(ptr3, r, g, b); 728 ptr3 += 3; 729 } 730 } 731 else { 732 /* Clear part of RGB buffer */ 733 GLint i, j; 734 for (i = 0; i < height; i++) { 735 GLchan *ptr3 = PIXELADDR3(x, (y + i)); 736 for (j = 0; j < width; j++) { 737 PACK_BGR(ptr3, r, g, b); 738 ptr3 += 3; 739 } 740 } 741 } 742 } 743 else { 744#if CHAN_TYPE == GL_UNSIGNED_BYTE 745 /* 4-byte pixel value */ 746 GLuint clearPixel; 747 GLchan *clr = (GLchan *) &clearPixel; 748 clr[osmesa->rInd] = ctx->Color.ClearColor[0]; 749 clr[osmesa->gInd] = ctx->Color.ClearColor[1]; 750 clr[osmesa->bInd] = ctx->Color.ClearColor[2]; 751 clr[osmesa->aInd] = ctx->Color.ClearColor[3]; 752 if (all) { 753 /* Clear whole RGBA buffer */ 754 const GLuint n = osmesa->rowlength * osmesa->height; 755 GLuint *ptr4 = (GLuint *) osmesa->buffer; 756 GLuint i; 757 if (clearPixel) { 758 for (i = 0; i < n; i++) { 759 *ptr4++ = clearPixel; 760 } 761 } 762 else { 763 BZERO(ptr4, n * sizeof(GLuint)); 764 } 765 } 766 else { 767 /* Clear part of RGBA buffer */ 768 GLint i, j; 769 for (i = 0; i < height; i++) { 770 GLuint *ptr4 = (GLuint *) PIXELADDR4(x, (y + i)); 771 for (j = 0; j < width; j++) { 772 *ptr4++ = clearPixel; 773 } 774 } 775 } 776#else 777 const GLchan r = ctx->Color.ClearColor[0]; 778 const GLchan g = ctx->Color.ClearColor[1]; 779 const GLchan b = ctx->Color.ClearColor[2]; 780 const GLchan a = ctx->Color.ClearColor[3]; 781 if (all) { 782 /* Clear whole RGBA buffer */ 783 const GLuint n = osmesa->rowlength * osmesa->height; 784 GLchan *p = (GLchan *) osmesa->buffer; 785 GLuint i; 786 for (i = 0; i < n; i++) { 787 PACK_RGBA(p, r, g, b, a); 788 p += 4; 789 } 790 } 791 else { 792 /* Clear part of RGBA buffer */ 793 GLint i, j; 794 for (i = 0; i < height; i++) { 795 GLchan *p = PIXELADDR4(x, (y + i)); 796 for (j = 0; j < width; j++) { 797 PACK_RGBA(p, r, g, b, a); 798 p += 4; 799 } 800 } 801 } 802 803#endif 804 } 805 mask &= ~DD_FRONT_LEFT_BIT; 806 } 807 } 808 809 if (mask) 810 _swrast_Clear( ctx, mask, all, x, y, width, height ); 811} 812 813 814 815static void buffer_size( GLcontext *ctx, GLuint *width, GLuint *height ) 816{ 817 OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 818 *width = osmesa->width; 819 *height = osmesa->height; 820} 821 822 823/**********************************************************************/ 824/***** Read/write spans/arrays of RGBA pixels *****/ 825/**********************************************************************/ 826 827/* Write RGBA pixels to an RGBA (or permuted) buffer. */ 828static void 829write_rgba_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 830 CONST GLchan rgba[][4], const GLubyte mask[] ) 831{ 832 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 833 GLchan *p = PIXELADDR4(x, y); 834 GLuint i; 835 if (mask) { 836 for (i = 0; i < n; i++, p += 4) { 837 if (mask[i]) { 838 PACK_RGBA(p, rgba[i][RCOMP], rgba[i][GCOMP], 839 rgba[i][BCOMP], rgba[i][ACOMP]); 840 } 841 } 842 } 843 else { 844 for (i = 0; i < n; i++, p += 4) { 845 PACK_RGBA(p, rgba[i][RCOMP], rgba[i][GCOMP], 846 rgba[i][BCOMP], rgba[i][ACOMP]); 847 } 848 } 849} 850 851 852/* Write RGBA pixels to an RGBA buffer. This is the fastest span-writer. */ 853static void 854write_rgba_span_rgba( const GLcontext *ctx, GLuint n, GLint x, GLint y, 855 CONST GLchan rgba[][4], const GLubyte mask[] ) 856{ 857 OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 858 GLuint *ptr4 = (GLuint *) PIXELADDR4(x, y); 859 const GLuint *rgba4 = (const GLuint *) rgba; 860 GLuint i; 861 ASSERT(CHAN_TYPE == GL_UNSIGNED_BYTE); 862 if (mask) { 863 for (i = 0; i < n; i++) { 864 if (mask[i]) { 865 ptr4[i] = rgba4[i]; 866 } 867 } 868 } 869 else { 870 MEMCPY( ptr4, rgba4, n * 4 ); 871 } 872} 873 874 875/* Write RGB pixels to an RGBA (or permuted) buffer. */ 876static void 877write_rgb_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 878 CONST GLchan rgb[][3], const GLubyte mask[] ) 879{ 880 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 881 GLchan *p = PIXELADDR4(x, y); 882 GLuint i; 883 if (mask) { 884 for (i = 0; i < n; i++, p+=4) { 885 if (mask[i]) { 886 PACK_RGBA(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP], 255); 887 } 888 } 889 } 890 else { 891 for (i = 0; i < n; i++, p+=4) { 892 PACK_RGBA(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP], 255); 893 } 894 } 895} 896 897 898 899static void 900write_monocolor_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 901 const GLchan color[4], const GLubyte mask[] ) 902{ 903 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 904 GLchan *p = PIXELADDR4(x, y); 905 GLuint i; 906 for (i = 0; i < n; i++, p += 4) { 907 if (mask[i]) { 908 PACK_RGBA(p, color[RCOMP], color[GCOMP], color[BCOMP], color[ACOMP]); 909 } 910 } 911} 912 913 914 915static void 916write_rgba_pixels( const GLcontext *ctx, GLuint n, 917 const GLint x[], const GLint y[], 918 CONST GLchan rgba[][4], const GLubyte mask[] ) 919{ 920 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 921 GLuint i; 922 for (i = 0; i < n; i++) { 923 if (mask[i]) { 924 GLchan *p = PIXELADDR4(x[i], y[i]); 925 PACK_RGBA(p, rgba[i][RCOMP], rgba[i][GCOMP], 926 rgba[i][BCOMP], rgba[i][ACOMP]); 927 } 928 } 929} 930 931 932 933static void 934write_monocolor_pixels( const GLcontext *ctx, GLuint n, 935 const GLint x[], const GLint y[], 936 const GLchan color[4], const GLubyte mask[] ) 937{ 938 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 939 GLuint i; 940 for (i = 0; i < n; i++) { 941 if (mask[i]) { 942 GLchan *p = PIXELADDR4(x[i], y[i]); 943 PACK_RGBA(p, color[RCOMP], color[GCOMP], color[BCOMP], color[ACOMP]); 944 } 945 } 946} 947 948 949static void 950read_rgba_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 951 GLchan rgba[][4] ) 952{ 953 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 954 GLuint i; 955 GLchan *p = PIXELADDR4(x, y); 956 for (i = 0; i < n; i++, p += 4) { 957 rgba[i][RCOMP] = UNPACK_RED(p); 958 rgba[i][GCOMP] = UNPACK_GREEN(p); 959 rgba[i][BCOMP] = UNPACK_BLUE(p); 960 rgba[i][ACOMP] = UNPACK_ALPHA(p); 961 } 962} 963 964 965/* Read RGBA pixels from an RGBA buffer */ 966static void 967read_rgba_span_rgba( const GLcontext *ctx, GLuint n, GLint x, GLint y, 968 GLchan rgba[][4] ) 969{ 970 OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 971 GLuint *ptr4 = (GLuint *) PIXELADDR4(x, y); 972 MEMCPY( rgba, ptr4, n * 4 * sizeof(GLchan) ); 973} 974 975 976static void 977read_rgba_pixels( const GLcontext *ctx, 978 GLuint n, const GLint x[], const GLint y[], 979 GLchan rgba[][4], const GLubyte mask[] ) 980{ 981 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 982 GLuint i; 983 for (i = 0; i < n; i++) { 984 if (mask[i]) { 985 const GLchan *p = PIXELADDR4(x[i], y[i]); 986 rgba[i][RCOMP] = UNPACK_RED(p); 987 rgba[i][GCOMP] = UNPACK_GREEN(p); 988 rgba[i][BCOMP] = UNPACK_BLUE(p); 989 rgba[i][ACOMP] = UNPACK_ALPHA(p); 990 } 991 } 992} 993 994/**********************************************************************/ 995/***** 3 byte RGB pixel support funcs *****/ 996/**********************************************************************/ 997 998/* Write RGBA pixels to an RGB buffer. */ 999static void 1000write_rgba_span_RGB( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1001 CONST GLchan rgba[][4], const GLubyte mask[] ) 1002{ 1003 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1004 GLchan *p = PIXELADDR3(x, y); 1005 GLuint i; 1006 if (mask) { 1007 for (i = 0; i < n; i++, p += 3) { 1008 if (mask[i]) { 1009 PACK_RGB(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1010 } 1011 } 1012 } 1013 else { 1014 for (i = 0; i < n; i++, p += 3) { 1015 PACK_RGB(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1016 } 1017 } 1018} 1019 1020/* Write RGBA pixels to an BGR buffer. */ 1021static void 1022write_rgba_span_BGR( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1023 CONST GLchan rgba[][4], const GLubyte mask[] ) 1024{ 1025 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1026 GLchan *p = PIXELADDR3(x, y); 1027 GLuint i; 1028 if (mask) { 1029 for (i = 0; i < n; i++, p += 3) { 1030 if (mask[i]) { 1031 PACK_BGR(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1032 } 1033 } 1034 } 1035 else { 1036 for (i = 0; i < n; i++, p += 3) { 1037 PACK_BGR(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1038 } 1039 } 1040} 1041 1042/* Write RGB pixels to an RGB buffer. */ 1043static void 1044write_rgb_span_RGB( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1045 CONST GLchan rgb[][3], const GLubyte mask[] ) 1046{ 1047 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1048 GLchan *p = PIXELADDR3(x, y); 1049 GLuint i; 1050 if (mask) { 1051 for (i = 0; i < n; i++, p += 3) { 1052 if (mask[i]) { 1053 PACK_RGB(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP]); 1054 } 1055 } 1056 } 1057 else { 1058 for (i = 0; i < n; i++, p += 3) { 1059 PACK_RGB(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP]); 1060 } 1061 } 1062} 1063 1064/* Write RGB pixels to an BGR buffer. */ 1065static void 1066write_rgb_span_BGR( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1067 CONST GLchan rgb[][3], const GLubyte mask[] ) 1068{ 1069 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1070 GLchan *p = PIXELADDR3(x, y); 1071 GLuint i; 1072 if (mask) { 1073 for (i = 0; i < n; i++, p += 3) { 1074 if (mask[i]) { 1075 PACK_BGR(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP]); 1076 } 1077 } 1078 } 1079 else { 1080 for (i = 0; i < n; i++, p += 3) { 1081 PACK_BGR(p, rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP]); 1082 } 1083 } 1084} 1085 1086 1087static void 1088write_monocolor_span_RGB( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1089 const GLchan color[4], const GLubyte mask[] ) 1090{ 1091 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1092 GLchan *p = PIXELADDR3(x, y); 1093 GLuint i; 1094 for (i = 0; i < n; i++, p += 3) { 1095 if (mask[i]) { 1096 PACK_RGB(p, color[RCOMP], color[GCOMP], color[BCOMP]); 1097 } 1098 } 1099} 1100 1101static void 1102write_monocolor_span_BGR( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1103 const GLchan color[4], const GLubyte mask[] ) 1104{ 1105 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1106 GLchan *p = PIXELADDR3(x, y); 1107 GLuint i; 1108 for (i = 0; i < n; i++, p += 3) { 1109 if (mask[i]) { 1110 PACK_BGR(p, color[RCOMP], color[GCOMP], color[BCOMP]); 1111 } 1112 } 1113} 1114 1115static void 1116write_rgba_pixels_RGB( const GLcontext *ctx, GLuint n, 1117 const GLint x[], const GLint y[], 1118 CONST GLchan rgba[][4], const GLubyte mask[] ) 1119{ 1120 const OSMesaContext osmesa = (const OSMesaContext) ctx; 1121 GLuint i; 1122 for (i = 0; i < n; i++) { 1123 if (mask[i]) { 1124 GLchan *p = PIXELADDR3(x[i], y[i]); 1125 PACK_RGB(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1126 } 1127 } 1128} 1129 1130static void 1131write_rgba_pixels_BGR( const GLcontext *ctx, GLuint n, 1132 const GLint x[], const GLint y[], 1133 CONST GLchan rgba[][4], const GLubyte mask[] ) 1134{ 1135 const OSMesaContext osmesa = (const OSMesaContext) ctx; 1136 GLuint i; 1137 for (i = 0; i < n; i++) { 1138 if (mask[i]) { 1139 GLchan *p = PIXELADDR3(x[i], y[i]); 1140 PACK_BGR(p, rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 1141 } 1142 } 1143} 1144 1145static void 1146write_monocolor_pixels_RGB( const GLcontext *ctx, 1147 GLuint n, const GLint x[], const GLint y[], 1148 const GLchan color[4], const GLubyte mask[] ) 1149{ 1150 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1151 GLuint i; 1152 for (i = 0; i < n; i++) { 1153 if (mask[i]) { 1154 GLchan *p = PIXELADDR3(x[i], y[i]); 1155 PACK_RGB(p, color[RCOMP], color[GCOMP], color[BCOMP]); 1156 } 1157 } 1158} 1159 1160static void 1161write_monocolor_pixels_BGR( const GLcontext *ctx, 1162 GLuint n, const GLint x[], const GLint y[], 1163 const GLchan color[4], const GLubyte mask[] ) 1164{ 1165 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1166 GLuint i; 1167 for (i = 0; i < n; i++) { 1168 if (mask[i]) { 1169 GLchan *p = PIXELADDR3(x[i], y[i]); 1170 PACK_BGR(p, color[RCOMP], color[GCOMP], color[BCOMP]); 1171 } 1172 } 1173} 1174 1175static void 1176read_rgba_span3( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1177 GLchan rgba[][4] ) 1178{ 1179 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1180 GLuint i; 1181 const GLchan *p = PIXELADDR3(x, y); 1182 for (i = 0; i < n; i++, p += 3) { 1183 rgba[i][RCOMP] = UNPACK_RED(p); 1184 rgba[i][GCOMP] = UNPACK_GREEN(p); 1185 rgba[i][BCOMP] = UNPACK_BLUE(p); 1186 rgba[i][ACOMP] = 255; 1187 } 1188} 1189 1190static void 1191read_rgba_pixels3( const GLcontext *ctx, 1192 GLuint n, const GLint x[], const GLint y[], 1193 GLchan rgba[][4], const GLubyte mask[] ) 1194{ 1195 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1196 GLuint i; 1197 for (i = 0; i < n; i++) { 1198 if (mask[i]) { 1199 const GLchan *p = PIXELADDR3(x[i], y[i]); 1200 rgba[i][RCOMP] = UNPACK_RED(p); 1201 rgba[i][GCOMP] = UNPACK_GREEN(p); 1202 rgba[i][BCOMP] = UNPACK_BLUE(p); 1203 rgba[i][ACOMP] = 255; 1204 } 1205 } 1206} 1207 1208 1209/**********************************************************************/ 1210/***** Read/write spans/arrays of CI pixels *****/ 1211/**********************************************************************/ 1212 1213/* Write 32-bit color index to buffer */ 1214static void 1215write_index32_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1216 const GLuint index[], const GLubyte mask[] ) 1217{ 1218 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1219 GLchan *ptr1 = PIXELADDR1(x, y); 1220 GLuint i; 1221 if (mask) { 1222 for (i=0;i<n;i++,ptr1++) { 1223 if (mask[i]) { 1224 *ptr1 = (GLchan) index[i]; 1225 } 1226 } 1227 } 1228 else { 1229 for (i=0;i<n;i++,ptr1++) { 1230 *ptr1 = (GLchan) index[i]; 1231 } 1232 } 1233} 1234 1235 1236/* Write 8-bit color index to buffer */ 1237static void 1238write_index8_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1239 const GLubyte index[], const GLubyte mask[] ) 1240{ 1241 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1242 GLchan *ptr1 = PIXELADDR1(x, y); 1243 GLuint i; 1244 if (mask) { 1245 for (i=0;i<n;i++,ptr1++) { 1246 if (mask[i]) { 1247 *ptr1 = (GLchan) index[i]; 1248 } 1249 } 1250 } 1251 else { 1252 MEMCPY(ptr1, index, n * sizeof(GLchan)); 1253 } 1254} 1255 1256 1257static void 1258write_monoindex_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, 1259 GLuint colorIndex, const GLubyte mask[] ) 1260{ 1261 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1262 GLchan *ptr1 = PIXELADDR1(x, y); 1263 GLuint i; 1264 for (i=0;i<n;i++,ptr1++) { 1265 if (mask[i]) { 1266 *ptr1 = (GLchan) colorIndex; 1267 } 1268 } 1269} 1270 1271 1272static void 1273write_index_pixels( const GLcontext *ctx, 1274 GLuint n, const GLint x[], const GLint y[], 1275 const GLuint index[], const GLubyte mask[] ) 1276{ 1277 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1278 GLuint i; 1279 for (i=0;i<n;i++) { 1280 if (mask[i]) { 1281 GLchan *ptr1 = PIXELADDR1(x[i], y[i]); 1282 *ptr1 = (GLchan) index[i]; 1283 } 1284 } 1285} 1286 1287 1288static void 1289write_monoindex_pixels( const GLcontext *ctx, 1290 GLuint n, const GLint x[], const GLint y[], 1291 GLuint colorIndex, const GLubyte mask[] ) 1292{ 1293 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1294 GLuint i; 1295 for (i=0;i<n;i++) { 1296 if (mask[i]) { 1297 GLchan *ptr1 = PIXELADDR1(x[i], y[i]); 1298 *ptr1 = (GLchan) colorIndex; 1299 } 1300 } 1301} 1302 1303 1304static void 1305read_index_span( const GLcontext *ctx, 1306 GLuint n, GLint x, GLint y, GLuint index[] ) 1307{ 1308 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1309 GLuint i; 1310 const GLchan *ptr1 = (const GLchan *) PIXELADDR1(x, y); 1311 for (i=0;i<n;i++,ptr1++) { 1312 index[i] = (GLuint) *ptr1; 1313 } 1314} 1315 1316 1317static void 1318read_index_pixels( const GLcontext *ctx, 1319 GLuint n, const GLint x[], const GLint y[], 1320 GLuint index[], const GLubyte mask[] ) 1321{ 1322 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1323 GLuint i; 1324 for (i=0;i<n;i++) { 1325 if (mask[i] ) { 1326 const GLchan *ptr1 = PIXELADDR1(x[i], y[i]); 1327 index[i] = (GLuint) *ptr1; 1328 } 1329 } 1330} 1331 1332 1333 1334/**********************************************************************/ 1335/***** Optimized line rendering *****/ 1336/**********************************************************************/ 1337 1338 1339/* 1340 * Draw a flat-shaded, RGB line into an osmesa buffer. 1341 */ 1342static void 1343flat_rgba_line( GLcontext *ctx, const SWvertex *vert0, const SWvertex *vert1 ) 1344{ 1345 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1346 const GLchan *color = vert0->color; 1347 1348#define INTERP_XY 1 1349#define CLIP_HACK 1 1350#define PLOT(X, Y) \ 1351do { \ 1352 GLchan *p = PIXELADDR4(X, Y); \ 1353 PACK_RGBA(p, color[0], color[1], color[2], color[3]); \ 1354} while (0) 1355 1356#ifdef WIN32 1357#include "..\swrast\s_linetemp.h" 1358#else 1359#include "swrast/s_linetemp.h" 1360#endif 1361} 1362 1363 1364/* 1365 * Draw a flat-shaded, Z-less, RGB line into an osmesa buffer. 1366 */ 1367static void 1368flat_rgba_z_line(GLcontext *ctx, const SWvertex *vert0, const SWvertex *vert1) 1369{ 1370 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1371 const GLchan *color = vert0->color; 1372 1373#define INTERP_XY 1 1374#define INTERP_Z 1 1375#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 1376#define CLIP_HACK 1 1377#define PLOT(X, Y) \ 1378do { \ 1379 if (Z < *zPtr) { \ 1380 GLchan *p = PIXELADDR4(X, Y); \ 1381 PACK_RGBA(p, color[RCOMP], color[GCOMP], \ 1382 color[BCOMP], color[ACOMP]); \ 1383 *zPtr = Z; \ 1384 } \ 1385} while (0) 1386 1387 1388#ifdef WIN32 1389#include "..\swrast\s_linetemp.h" 1390#else 1391#include "swrast/s_linetemp.h" 1392#endif 1393} 1394 1395 1396/* 1397 * Draw a flat-shaded, alpha-blended, RGB line into an osmesa buffer. 1398 * XXX update for GLchan 1399 */ 1400static void 1401flat_blend_rgba_line( GLcontext *ctx, 1402 const SWvertex *vert0, const SWvertex *vert1 ) 1403{ 1404 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1405 const GLint rshift = osmesa->rshift; 1406 const GLint gshift = osmesa->gshift; 1407 const GLint bshift = osmesa->bshift; 1408 const GLint avalue = vert0->color[3]; 1409 const GLint msavalue = 255 - avalue; 1410 const GLint rvalue = vert0->color[0]*avalue; 1411 const GLint gvalue = vert0->color[1]*avalue; 1412 const GLint bvalue = vert0->color[2]*avalue; 1413 1414#define INTERP_XY 1 1415#define CLIP_HACK 1 1416#define PLOT(X,Y) \ 1417 { GLuint *ptr4 = (GLuint *) PIXELADDR4(X, Y); \ 1418 GLuint pixel = 0; \ 1419 pixel |=((((((*ptr4) >> rshift) & 0xff)*msavalue+rvalue)>>8) << rshift);\ 1420 pixel |=((((((*ptr4) >> gshift) & 0xff)*msavalue+gvalue)>>8) << gshift);\ 1421 pixel |=((((((*ptr4) >> bshift) & 0xff)*msavalue+bvalue)>>8) << bshift);\ 1422 *ptr4 = pixel; \ 1423 } 1424 1425#ifdef WIN32 1426#include "..\swrast\s_linetemp.h" 1427#else 1428#include "swrast/s_linetemp.h" 1429#endif 1430} 1431 1432 1433/* 1434 * Draw a flat-shaded, Z-less, alpha-blended, RGB line into an osmesa buffer. 1435 * XXX update for GLchan 1436 */ 1437static void 1438flat_blend_rgba_z_line( GLcontext *ctx, 1439 const SWvertex *vert0, const SWvertex *vert1 ) 1440{ 1441 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1442 const GLint rshift = osmesa->rshift; 1443 const GLint gshift = osmesa->gshift; 1444 const GLint bshift = osmesa->bshift; 1445 const GLint avalue = vert0->color[3]; 1446 const GLint msavalue = 256 - avalue; 1447 const GLint rvalue = vert0->color[0]*avalue; 1448 const GLint gvalue = vert0->color[1]*avalue; 1449 const GLint bvalue = vert0->color[2]*avalue; 1450 1451#define INTERP_XY 1 1452#define INTERP_Z 1 1453#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 1454#define CLIP_HACK 1 1455#define PLOT(X,Y) \ 1456 if (Z < *zPtr) { \ 1457 GLuint *ptr4 = (GLuint *) PIXELADDR4(X, Y); \ 1458 GLuint pixel = 0; \ 1459 pixel |=((((((*ptr4) >> rshift) & 0xff)*msavalue+rvalue)>>8) << rshift); \ 1460 pixel |=((((((*ptr4) >> gshift) & 0xff)*msavalue+gvalue)>>8) << gshift); \ 1461 pixel |=((((((*ptr4) >> bshift) & 0xff)*msavalue+bvalue)>>8) << bshift); \ 1462 *ptr4 = pixel; \ 1463 } 1464 1465#ifdef WIN32 1466#include "..\swrast\s_linetemp.h" 1467#else 1468#include "swrast/s_linetemp.h" 1469#endif 1470} 1471 1472 1473/* 1474 * Draw a flat-shaded, Z-less, alpha-blended, RGB line into an osmesa buffer. 1475 * XXX update for GLchan 1476 */ 1477static void 1478flat_blend_rgba_z_line_write( GLcontext *ctx, 1479 const SWvertex *vert0, const SWvertex *vert1 ) 1480{ 1481 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1482 const GLint rshift = osmesa->rshift; 1483 const GLint gshift = osmesa->gshift; 1484 const GLint bshift = osmesa->bshift; 1485 const GLint avalue = vert0->color[3]; 1486 const GLint msavalue = 256 - avalue; 1487 const GLint rvalue = vert0->color[0]*avalue; 1488 const GLint gvalue = vert0->color[1]*avalue; 1489 const GLint bvalue = vert0->color[2]*avalue; 1490 1491#define INTERP_XY 1 1492#define INTERP_Z 1 1493#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 1494#define CLIP_HACK 1 1495#define PLOT(X,Y) \ 1496 if (Z < *zPtr) { \ 1497 GLuint *ptr4 = (GLuint *) PIXELADDR4(X, Y); \ 1498 GLuint pixel = 0; \ 1499 pixel |=((((((*ptr4) >> rshift) & 0xff)*msavalue+rvalue)>>8) << rshift); \ 1500 pixel |=((((((*ptr4) >> gshift) & 0xff)*msavalue+gvalue)>>8) << gshift); \ 1501 pixel |=((((((*ptr4) >> bshift) & 0xff)*msavalue+bvalue)>>8) << bshift); \ 1502 *ptr4 = pixel; \ 1503 *zPtr = Z; \ 1504 } 1505 1506#ifdef WIN32 1507#include "..\swrast\s_linetemp.h" 1508#else 1509#include "swrast/s_linetemp.h" 1510#endif 1511} 1512 1513 1514/* 1515 * Analyze context state to see if we can provide a fast line drawing 1516 * function, like those in lines.c. Otherwise, return NULL. 1517 */ 1518static swrast_line_func 1519osmesa_choose_line_function( GLcontext *ctx ) 1520{ 1521 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1522 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 1523 1524 if (CHAN_BITS != 8) return NULL; 1525 if (ctx->RenderMode != GL_RENDER) return NULL; 1526 if (ctx->Line.SmoothFlag) return NULL; 1527 if (ctx->Texture._ReallyEnabled) return NULL; 1528 if (ctx->Light.ShadeModel != GL_FLAT) return NULL; 1529 if (ctx->Line.Width != 1.0F) return NULL; 1530 if (ctx->Line.StippleFlag) return NULL; 1531 if (ctx->Line.SmoothFlag) return NULL; 1532 if (osmesa->format != OSMESA_RGBA && 1533 osmesa->format != OSMESA_BGRA && 1534 osmesa->format != OSMESA_ARGB) return NULL; 1535 1536 if (swrast->_RasterMask==DEPTH_BIT 1537 && ctx->Depth.Func==GL_LESS 1538 && ctx->Depth.Mask==GL_TRUE 1539 && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { 1540 return flat_rgba_z_line; 1541 } 1542 1543 if (swrast->_RasterMask == 0) { 1544 return flat_rgba_line; 1545 } 1546 1547 if (swrast->_RasterMask==(DEPTH_BIT|BLEND_BIT) 1548 && ctx->Depth.Func==GL_LESS 1549 && ctx->Depth.Mask==GL_TRUE 1550 && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS 1551 && ctx->Color.BlendSrcRGB==GL_SRC_ALPHA 1552 && ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA 1553 && ctx->Color.BlendSrcA==GL_SRC_ALPHA 1554 && ctx->Color.BlendDstA==GL_ONE_MINUS_SRC_ALPHA 1555 && ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { 1556 return flat_blend_rgba_z_line_write; 1557 } 1558 1559 if (swrast->_RasterMask==(DEPTH_BIT|BLEND_BIT) 1560 && ctx->Depth.Func==GL_LESS 1561 && ctx->Depth.Mask==GL_FALSE 1562 && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS 1563 && ctx->Color.BlendSrcRGB==GL_SRC_ALPHA 1564 && ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA 1565 && ctx->Color.BlendSrcA==GL_SRC_ALPHA 1566 && ctx->Color.BlendDstA==GL_ONE_MINUS_SRC_ALPHA 1567 && ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { 1568 return flat_blend_rgba_z_line; 1569 } 1570 1571 if (swrast->_RasterMask==BLEND_BIT 1572 && ctx->Color.BlendSrcRGB==GL_SRC_ALPHA 1573 && ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA 1574 && ctx->Color.BlendSrcA==GL_SRC_ALPHA 1575 && ctx->Color.BlendDstA==GL_ONE_MINUS_SRC_ALPHA 1576 && ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { 1577 return flat_blend_rgba_line; 1578 } 1579 1580 return NULL; 1581} 1582 1583 1584/**********************************************************************/ 1585/***** Optimized triangle rendering *****/ 1586/**********************************************************************/ 1587 1588 1589/* 1590 * Smooth-shaded, z-less triangle, RGBA color. 1591 */ 1592static void smooth_rgba_z_triangle( GLcontext *ctx, 1593 const SWvertex *v0, 1594 const SWvertex *v1, 1595 const SWvertex *v2 ) 1596{ 1597 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1598 1599#define INTERP_Z 1 1600#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 1601#define INTERP_RGB 1 1602#define INTERP_ALPHA 1 1603#define INNER_LOOP( LEFT, RIGHT, Y ) \ 1604{ \ 1605 GLint i, len = RIGHT-LEFT; \ 1606 GLchan *img = PIXELADDR4(LEFT, Y); \ 1607 for (i = 0; i < len; i++, img += 4) { \ 1608 GLdepth z = FixedToDepth(ffz); \ 1609 if (z < zRow[i]) { \ 1610 PACK_RGBA(img, FixedToInt(ffr), FixedToInt(ffg), \ 1611 FixedToInt(ffb), FixedToInt(ffa)); \ 1612 zRow[i] = z; \ 1613 } \ 1614 ffr += fdrdx; ffg += fdgdx; ffb += fdbdx; ffa += fdadx;\ 1615 ffz += fdzdx; \ 1616 } \ 1617} 1618#ifdef WIN32 1619#include "..\swrast\s_tritemp.h" 1620#else 1621#include "swrast/s_tritemp.h" 1622#endif 1623} 1624 1625 1626 1627 1628/* 1629 * Flat-shaded, z-less triangle, RGBA color. 1630 */ 1631static void flat_rgba_z_triangle( GLcontext *ctx, 1632 const SWvertex *v0, 1633 const SWvertex *v1, 1634 const SWvertex *v2 ) 1635{ 1636 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1637#define INTERP_Z 1 1638#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 1639#define SETUP_CODE \ 1640 GLuint pixel; \ 1641 PACK_RGBA((GLchan *) &pixel, v0->color[0], v0->color[1], \ 1642 v0->color[2], v0->color[3]); 1643 1644#define INNER_LOOP( LEFT, RIGHT, Y ) \ 1645{ \ 1646 GLint i, len = RIGHT-LEFT; \ 1647 GLuint *img = (GLuint *) PIXELADDR4(LEFT, Y); \ 1648 for (i=0;i<len;i++) { \ 1649 GLdepth z = FixedToDepth(ffz); \ 1650 if (z < zRow[i]) { \ 1651 img[i] = pixel; \ 1652 zRow[i] = z; \ 1653 } \ 1654 ffz += fdzdx; \ 1655 } \ 1656} 1657#ifdef WIN32 1658#include "..\swrast\s_tritemp.h" 1659#else 1660#include "swrast/s_tritemp.h" 1661#endif 1662} 1663 1664 1665 1666/* 1667 * Return pointer to an accelerated triangle function if possible. 1668 */ 1669static swrast_tri_func 1670osmesa_choose_triangle_function( GLcontext *ctx ) 1671{ 1672 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1673 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 1674 1675 if (CHAN_BITS != 8) return (swrast_tri_func) NULL; 1676 if (ctx->RenderMode != GL_RENDER) return (swrast_tri_func) NULL; 1677 if (ctx->Polygon.SmoothFlag) return (swrast_tri_func) NULL; 1678 if (ctx->Polygon.StippleFlag) return (swrast_tri_func) NULL; 1679 if (ctx->Texture._ReallyEnabled) return (swrast_tri_func) NULL; 1680 if (osmesa->format != OSMESA_RGBA && 1681 osmesa->format != OSMESA_BGRA && 1682 osmesa->format != OSMESA_ARGB) return (swrast_tri_func) NULL; 1683 1684 if (swrast->_RasterMask == DEPTH_BIT && 1685 ctx->Depth.Func == GL_LESS && 1686 ctx->Depth.Mask == GL_TRUE && 1687 ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { 1688 if (ctx->Light.ShadeModel == GL_SMOOTH) { 1689 return smooth_rgba_z_triangle; 1690 } 1691 else { 1692 return flat_rgba_z_triangle; 1693 } 1694 } 1695 return (swrast_tri_func) NULL; 1696} 1697 1698 1699 1700/* Override for the swrast triangle-selection function. Try to use one 1701 * of our internal triangle functions, otherwise fall back to the 1702 * standard swrast functions. 1703 */ 1704static void osmesa_choose_triangle( GLcontext *ctx ) 1705{ 1706 SWcontext *swrast = SWRAST_CONTEXT(ctx); 1707 1708 swrast->Triangle = osmesa_choose_triangle_function( ctx ); 1709 if (!swrast->Triangle) 1710 _swrast_choose_triangle( ctx ); 1711} 1712 1713static void osmesa_choose_line( GLcontext *ctx ) 1714{ 1715 SWcontext *swrast = SWRAST_CONTEXT(ctx); 1716 1717 swrast->Line = osmesa_choose_line_function( ctx ); 1718 if (!swrast->Line) 1719 _swrast_choose_line( ctx ); 1720} 1721 1722 1723#define OSMESA_NEW_LINE (_NEW_LINE | \ 1724 _NEW_TEXTURE | \ 1725 _NEW_LIGHT | \ 1726 _NEW_DEPTH | \ 1727 _NEW_RENDERMODE | \ 1728 _SWRAST_NEW_RASTERMASK) 1729 1730#define OSMESA_NEW_TRIANGLE (_NEW_POLYGON | \ 1731 _NEW_TEXTURE | \ 1732 _NEW_LIGHT | \ 1733 _NEW_DEPTH | \ 1734 _NEW_RENDERMODE | \ 1735 _SWRAST_NEW_RASTERMASK) 1736 1737 1738/* Extend the software rasterizer with our line and triangle 1739 * functions. 1740 */ 1741static void osmesa_register_swrast_functions( GLcontext *ctx ) 1742{ 1743 SWcontext *swrast = SWRAST_CONTEXT( ctx ); 1744 1745 swrast->choose_line = osmesa_choose_line; 1746 swrast->choose_triangle = osmesa_choose_triangle; 1747 1748 swrast->invalidate_line |= OSMESA_NEW_LINE; 1749 swrast->invalidate_triangle |= OSMESA_NEW_TRIANGLE; 1750} 1751 1752 1753static const GLubyte *get_string( GLcontext *ctx, GLenum name ) 1754{ 1755 (void) ctx; 1756 switch (name) { 1757 case GL_RENDERER: 1758 return (const GLubyte *) "Mesa OffScreen"; 1759 default: 1760 return NULL; 1761 } 1762} 1763 1764 1765static void osmesa_update_state( GLcontext *ctx, GLuint new_state ) 1766{ 1767 OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 1768 struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx ); 1769 TNLcontext *tnl = TNL_CONTEXT(ctx); 1770 1771 ASSERT((void *) osmesa == (void *) ctx->DriverCtx); 1772 1773 /* 1774 * XXX these function pointers could be initialized just once during 1775 * context creation since they don't depend on any state changes. 1776 */ 1777 1778 ctx->Driver.GetString = get_string; 1779 ctx->Driver.UpdateState = osmesa_update_state; 1780 ctx->Driver.SetDrawBuffer = set_draw_buffer; 1781 ctx->Driver.ResizeBuffersMESA = _swrast_alloc_buffers; 1782 ctx->Driver.GetBufferSize = buffer_size; 1783 1784 ctx->Driver.Accum = _swrast_Accum; 1785 ctx->Driver.Bitmap = _swrast_Bitmap; 1786 ctx->Driver.Clear = clear; 1787 ctx->Driver.CopyPixels = _swrast_CopyPixels; 1788 ctx->Driver.DrawPixels = _swrast_DrawPixels; 1789 ctx->Driver.ReadPixels = _swrast_ReadPixels; 1790 1791 ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format; 1792 ctx->Driver.TexImage1D = _mesa_store_teximage1d; 1793 ctx->Driver.TexImage2D = _mesa_store_teximage2d; 1794 ctx->Driver.TexImage3D = _mesa_store_teximage3d; 1795 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d; 1796 ctx->Driver.TexSubImage2D = _mesa_store_texsubimage2d; 1797 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d; 1798 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage; 1799 1800 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d; 1801 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d; 1802 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d; 1803 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d; 1804 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d; 1805 ctx->Driver.CopyColorTable = _swrast_CopyColorTable; 1806 ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable; 1807 ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; 1808 ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; 1809 1810 1811 /* RGB(A) span/pixel functions */ 1812 if (osmesa->format == OSMESA_RGB) { 1813 swdd->WriteRGBASpan = write_rgba_span_RGB; 1814 swdd->WriteRGBSpan = write_rgb_span_RGB; 1815 swdd->WriteMonoRGBASpan = write_monocolor_span_RGB; 1816 swdd->WriteRGBAPixels = write_rgba_pixels_RGB; 1817 swdd->WriteMonoRGBAPixels = write_monocolor_pixels_RGB; 1818 swdd->ReadRGBASpan = read_rgba_span3; 1819 swdd->ReadRGBAPixels = read_rgba_pixels3; 1820 } 1821 else if (osmesa->format == OSMESA_BGR) { 1822 swdd->WriteRGBASpan = write_rgba_span_BGR; 1823 swdd->WriteRGBSpan = write_rgb_span_BGR; 1824 swdd->WriteMonoRGBASpan = write_monocolor_span_BGR; 1825 swdd->WriteRGBAPixels = write_rgba_pixels_BGR; 1826 swdd->WriteMonoRGBAPixels = write_monocolor_pixels_BGR; 1827 swdd->ReadRGBASpan = read_rgba_span3; 1828 swdd->ReadRGBAPixels = read_rgba_pixels3; 1829 } 1830 else { 1831 /* 4 bytes / pixel in frame buffer */ 1832 swdd->WriteRGBSpan = write_rgb_span; 1833 swdd->WriteRGBAPixels = write_rgba_pixels; 1834 swdd->WriteMonoRGBASpan = write_monocolor_span; 1835 swdd->WriteMonoRGBAPixels = write_monocolor_pixels; 1836 if (osmesa->format == OSMESA_RGBA && 1837 CHAN_TYPE == GL_UNSIGNED_BYTE && 1838 RCOMP==0 && GCOMP==1 && BCOMP==2 && ACOMP==3) { 1839 /* special, fast case */ 1840 swdd->WriteRGBASpan = write_rgba_span_rgba; 1841 swdd->ReadRGBASpan = read_rgba_span_rgba; 1842 } 1843 else { 1844 swdd->WriteRGBASpan = write_rgba_span; 1845 swdd->ReadRGBASpan = read_rgba_span; 1846 } 1847 swdd->ReadRGBAPixels = read_rgba_pixels; 1848 } 1849 1850 /* CI span/pixel functions */ 1851 swdd->WriteCI32Span = write_index32_span; 1852 swdd->WriteCI8Span = write_index8_span; 1853 swdd->WriteMonoCISpan = write_monoindex_span; 1854 swdd->WriteCI32Pixels = write_index_pixels; 1855 swdd->WriteMonoCIPixels = write_monoindex_pixels; 1856 swdd->ReadCI32Span = read_index_span; 1857 swdd->ReadCI32Pixels = read_index_pixels; 1858 1859 swdd->SetReadBuffer = set_read_buffer; 1860 1861 tnl->Driver.RunPipeline = _tnl_run_pipeline; 1862 tnl->Driver.RenderStart = _swsetup_RenderStart; 1863 tnl->Driver.RenderFinish = _swsetup_RenderFinish; 1864 tnl->Driver.BuildProjectedVertices = _swsetup_BuildProjectedVertices; 1865 tnl->Driver.RenderPrimitive = _swsetup_RenderPrimitive; 1866 tnl->Driver.PointsFunc = _swsetup_Points; 1867 tnl->Driver.LineFunc = _swsetup_Line; 1868 tnl->Driver.TriangleFunc = _swsetup_Triangle; 1869 tnl->Driver.QuadFunc = _swsetup_Quad; 1870 tnl->Driver.ResetLineStipple = _swrast_ResetLineStipple; 1871 tnl->Driver.RenderInterp = _swsetup_RenderInterp; 1872 tnl->Driver.RenderCopyPV = _swsetup_RenderCopyPV; 1873 tnl->Driver.RenderClippedLine = _swsetup_RenderClippedLine; 1874 tnl->Driver.RenderClippedPolygon = _swsetup_RenderClippedPolygon; 1875 1876 1877 _swrast_InvalidateState( ctx, new_state ); 1878 _swsetup_InvalidateState( ctx, new_state ); 1879 _ac_InvalidateState( ctx, new_state ); 1880 _tnl_InvalidateState( ctx, new_state ); 1881} 1882