s_drawpix.c revision 27558a160a9fe91745728d7626995cd88f8fe339
1/* $Id: s_drawpix.c,v 1.46 2003/03/01 01:50:25 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 5.1 6 * 7 * Copyright (C) 1999-2003 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#include "glheader.h" 29#include "context.h" 30#include "convolve.h" 31#include "image.h" 32#include "macros.h" 33#include "imports.h" 34#include "pixel.h" 35 36#include "s_context.h" 37#include "s_drawpix.h" 38#include "s_pixeltex.h" 39#include "s_span.h" 40#include "s_stencil.h" 41#include "s_zoom.h" 42 43 44 45/* 46 * Given the dest position, size and skipPixels and skipRows values 47 * for a glDrawPixels command, perform clipping of the image bounds 48 * so the result lies withing the context's buffer bounds. 49 * Return: GL_TRUE if image is ready for drawing 50 * GL_FALSE if image was completely clipped away (draw nothing) 51 */ 52GLboolean 53_mesa_clip_pixelrect(const GLcontext *ctx, 54 GLint *destX, GLint *destY, 55 GLsizei *width, GLsizei *height, 56 GLint *skipPixels, GLint *skipRows) 57{ 58 const GLframebuffer *buffer = ctx->DrawBuffer; 59 60 /* left clipping */ 61 if (*destX < buffer->_Xmin) { 62 *skipPixels += (buffer->_Xmin - *destX); 63 *width -= (buffer->_Xmin - *destX); 64 *destX = buffer->_Xmin; 65 } 66 /* right clipping */ 67 if (*destX + *width > buffer->_Xmax) 68 *width -= (*destX + *width - buffer->_Xmax); 69 70 if (*width <= 0) 71 return GL_FALSE; 72 73 /* bottom clipping */ 74 if (*destY < buffer->_Ymin) { 75 *skipRows += (buffer->_Ymin - *destY); 76 *height -= (buffer->_Ymin - *destY); 77 *destY = buffer->_Ymin; 78 } 79 /* top clipping */ 80 if (*destY + *height > buffer->_Ymax) 81 *height -= (*destY + *height - buffer->_Ymax); 82 83 if (*height <= 0) 84 return GL_TRUE; 85 86 return GL_TRUE; 87} 88 89 90 91/* 92 * Try to do a fast and simple RGB(a) glDrawPixels. 93 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead 94 */ 95static GLboolean 96fast_draw_pixels(GLcontext *ctx, GLint x, GLint y, 97 GLsizei width, GLsizei height, 98 GLenum format, GLenum type, const GLvoid *pixels) 99{ 100 SWcontext *swrast = SWRAST_CONTEXT(ctx); 101 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 102 struct sw_span span; 103 104 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 105 106 if (!ctx->Current.RasterPosValid) { 107 return GL_TRUE; /* no-op */ 108 } 109 110 if (ctx->Depth.Test) 111 _mesa_span_default_z(ctx, &span); 112 if (ctx->Fog.Enabled) 113 _mesa_span_default_fog(ctx, &span); 114 if (ctx->Texture._EnabledUnits) 115 _mesa_span_default_texcoords(ctx, &span); 116 117 if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0 118 && ctx->Texture._EnabledUnits == 0 119 && unpack->Alignment == 1 120 && !unpack->SwapBytes 121 && !unpack->LsbFirst) { 122 123 GLint destX = x; 124 GLint destY = y; 125 GLint drawWidth = width; /* actual width drawn */ 126 GLint drawHeight = height; /* actual height drawn */ 127 GLint skipPixels = unpack->SkipPixels; 128 GLint skipRows = unpack->SkipRows; 129 GLint rowLength; 130 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */ 131 GLint zoomY0 = 0; 132 133 if (unpack->RowLength > 0) 134 rowLength = unpack->RowLength; 135 else 136 rowLength = width; 137 138 /* If we're not using pixel zoom then do all clipping calculations 139 * now. Otherwise, we'll let the _mesa_write_zoomed_*_span() functions 140 * handle the clipping. 141 */ 142 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 143 /* horizontal clipping */ 144 if (destX < ctx->DrawBuffer->_Xmin) { 145 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 146 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 147 destX = ctx->DrawBuffer->_Xmin; 148 } 149 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 150 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 151 if (drawWidth <= 0) 152 return GL_TRUE; 153 154 /* vertical clipping */ 155 if (destY < ctx->DrawBuffer->_Ymin) { 156 skipRows += (ctx->DrawBuffer->_Ymin - destY); 157 drawHeight -= (ctx->DrawBuffer->_Ymin - destY); 158 destY = ctx->DrawBuffer->_Ymin; 159 } 160 if (destY + drawHeight > ctx->DrawBuffer->_Ymax) 161 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax); 162 if (drawHeight <= 0) 163 return GL_TRUE; 164 } 165 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 166 /* upside-down image */ 167 /* horizontal clipping */ 168 if (destX < ctx->DrawBuffer->_Xmin) { 169 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 170 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 171 destX = ctx->DrawBuffer->_Xmin; 172 } 173 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 174 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 175 if (drawWidth <= 0) 176 return GL_TRUE; 177 178 /* vertical clipping */ 179 if (destY > ctx->DrawBuffer->_Ymax) { 180 skipRows += (destY - ctx->DrawBuffer->_Ymax); 181 drawHeight -= (destY - ctx->DrawBuffer->_Ymax); 182 destY = ctx->DrawBuffer->_Ymax; 183 } 184 if (destY - drawHeight < ctx->DrawBuffer->_Ymin) 185 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight)); 186 if (drawHeight <= 0) 187 return GL_TRUE; 188 } 189 else { 190 /* setup array of fragment Z value to pass to zoom function */ 191 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF); 192 GLint i; 193 if (drawWidth > MAX_WIDTH) 194 return GL_FALSE; /* fall back to general case path */ 195 for (i=0; i<drawWidth; i++) 196 zSpan[i] = z; 197 198 /* save Y value of first row */ 199 zoomY0 = IROUND(ctx->Current.RasterPos[1]); 200 } 201 202 203 /* 204 * Ready to draw! 205 * The window region at (destX, destY) of size (drawWidth, drawHeight) 206 * will be written to. 207 * We'll take pixel data from buffer pointed to by "pixels" but we'll 208 * skip "skipRows" rows and skip "skipPixels" pixels/row. 209 */ 210 211 if (format == GL_RGBA && type == CHAN_TYPE 212 && ctx->_ImageTransferState==0) { 213 if (ctx->Visual.rgbMode) { 214 GLchan *src = (GLchan *) pixels 215 + (skipRows * rowLength + skipPixels) * 4; 216 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 217 /* no zooming */ 218 GLint row; 219 for (row=0; row<drawHeight; row++) { 220 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 221 (CONST GLchan (*)[4]) src, NULL); 222 src += rowLength * 4; 223 destY++; 224 } 225 } 226 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 227 /* upside-down */ 228 GLint row; 229 for (row=0; row<drawHeight; row++) { 230 destY--; 231 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 232 (CONST GLchan (*)[4]) src, NULL); 233 src += rowLength * 4; 234 } 235 } 236 else { 237 /* with zooming */ 238 GLint row; 239 for (row=0; row<drawHeight; row++) { 240 span.x = destX; 241 span.y = destY; 242 span.end = drawWidth; 243 _mesa_write_zoomed_rgba_span(ctx, &span, 244 (CONST GLchan (*)[4]) src, zoomY0, 0); 245 src += rowLength * 4; 246 destY++; 247 } 248 } 249 } 250 return GL_TRUE; 251 } 252 else if (format == GL_RGB && type == CHAN_TYPE 253 && ctx->_ImageTransferState == 0) { 254 if (ctx->Visual.rgbMode) { 255 GLchan *src = (GLchan *) pixels 256 + (skipRows * rowLength + skipPixels) * 3; 257 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 258 GLint row; 259 for (row=0; row<drawHeight; row++) { 260 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 261 (CONST GLchan (*)[3]) src, NULL); 262 src += rowLength * 3; 263 destY++; 264 } 265 } 266 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 267 /* upside-down */ 268 GLint row; 269 for (row=0; row<drawHeight; row++) { 270 destY--; 271 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 272 (CONST GLchan (*)[3]) src, NULL); 273 src += rowLength * 3; 274 } 275 } 276 else { 277 /* with zooming */ 278 GLint row; 279 for (row=0; row<drawHeight; row++) { 280 span.x = destX; 281 span.y = destY; 282 span.end = drawWidth; 283 _mesa_write_zoomed_rgb_span(ctx, &span, 284 (CONST GLchan (*)[3]) src, zoomY0, 0); 285 src += rowLength * 3; 286 destY++; 287 } 288 } 289 } 290 return GL_TRUE; 291 } 292 else if (format == GL_LUMINANCE && type == CHAN_TYPE 293 && ctx->_ImageTransferState==0) { 294 if (ctx->Visual.rgbMode) { 295 GLchan *src = (GLchan *) pixels 296 + (skipRows * rowLength + skipPixels); 297 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 298 /* no zooming */ 299 GLint row; 300 ASSERT(drawWidth < MAX_WIDTH); 301 for (row=0; row<drawHeight; row++) { 302 GLint i; 303 for (i=0;i<drawWidth;i++) { 304 span.array->rgb[i][0] = src[i]; 305 span.array->rgb[i][1] = src[i]; 306 span.array->rgb[i][2] = src[i]; 307 } 308 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 309 (CONST GLchan (*)[3]) span.array->rgb, NULL); 310 src += rowLength; 311 destY++; 312 } 313 } 314 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 315 /* upside-down */ 316 GLint row; 317 ASSERT(drawWidth < MAX_WIDTH); 318 for (row=0; row<drawHeight; row++) { 319 GLint i; 320 for (i=0;i<drawWidth;i++) { 321 span.array->rgb[i][0] = src[i]; 322 span.array->rgb[i][1] = src[i]; 323 span.array->rgb[i][2] = src[i]; 324 } 325 destY--; 326 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 327 (CONST GLchan (*)[3]) span.array->rgb, NULL); 328 src += rowLength; 329 } 330 } 331 else { 332 /* with zooming */ 333 GLint row; 334 ASSERT(drawWidth < MAX_WIDTH); 335 for (row=0; row<drawHeight; row++) { 336 GLint i; 337 for (i=0;i<drawWidth;i++) { 338 span.array->rgb[i][0] = src[i]; 339 span.array->rgb[i][1] = src[i]; 340 span.array->rgb[i][2] = src[i]; 341 } 342 span.x = destX; 343 span.y = destY; 344 span.end = drawWidth; 345 _mesa_write_zoomed_rgb_span(ctx, &span, 346 (CONST GLchan (*)[3]) span.array->rgb, zoomY0, 0); 347 src += rowLength; 348 destY++; 349 } 350 } 351 } 352 return GL_TRUE; 353 } 354 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE 355 && ctx->_ImageTransferState == 0) { 356 if (ctx->Visual.rgbMode) { 357 GLchan *src = (GLchan *) pixels 358 + (skipRows * rowLength + skipPixels)*2; 359 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 360 /* no zooming */ 361 GLint row; 362 ASSERT(drawWidth < MAX_WIDTH); 363 for (row=0; row<drawHeight; row++) { 364 GLint i; 365 GLchan *ptr = src; 366 for (i=0;i<drawWidth;i++) { 367 span.array->rgba[i][0] = *ptr; 368 span.array->rgba[i][1] = *ptr; 369 span.array->rgba[i][2] = *ptr++; 370 span.array->rgba[i][3] = *ptr++; 371 } 372 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 373 (CONST GLchan (*)[4]) span.array->rgba, NULL); 374 src += rowLength*2; 375 destY++; 376 } 377 } 378 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 379 /* upside-down */ 380 GLint row; 381 ASSERT(drawWidth < MAX_WIDTH); 382 for (row=0; row<drawHeight; row++) { 383 GLint i; 384 GLchan *ptr = src; 385 for (i=0;i<drawWidth;i++) { 386 span.array->rgba[i][0] = *ptr; 387 span.array->rgba[i][1] = *ptr; 388 span.array->rgba[i][2] = *ptr++; 389 span.array->rgba[i][3] = *ptr++; 390 } 391 destY--; 392 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 393 (CONST GLchan (*)[4]) span.array->rgba, NULL); 394 src += rowLength*2; 395 } 396 } 397 else { 398 /* with zooming */ 399 GLint row; 400 ASSERT(drawWidth < MAX_WIDTH); 401 for (row=0; row<drawHeight; row++) { 402 GLchan *ptr = src; 403 GLint i; 404 for (i=0;i<drawWidth;i++) { 405 span.array->rgba[i][0] = *ptr; 406 span.array->rgba[i][1] = *ptr; 407 span.array->rgba[i][2] = *ptr++; 408 span.array->rgba[i][3] = *ptr++; 409 } 410 span.x = destX; 411 span.y = destY; 412 span.end = drawWidth; 413 _mesa_write_zoomed_rgba_span(ctx, &span, 414 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0); 415 src += rowLength*2; 416 destY++; 417 } 418 } 419 } 420 return GL_TRUE; 421 } 422 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) { 423 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels; 424 if (ctx->Visual.rgbMode) { 425 /* convert CI data to RGBA */ 426 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 427 /* no zooming */ 428 GLint row; 429 for (row=0; row<drawHeight; row++) { 430 ASSERT(drawWidth < MAX_WIDTH); 431 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); 432 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 433 (const GLchan (*)[4]) span.array->rgba, NULL); 434 src += rowLength; 435 destY++; 436 } 437 return GL_TRUE; 438 } 439 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 440 /* upside-down */ 441 GLint row; 442 for (row=0; row<drawHeight; row++) { 443 ASSERT(drawWidth < MAX_WIDTH); 444 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); 445 destY--; 446 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 447 (CONST GLchan (*)[4]) span.array->rgba, NULL); 448 src += rowLength; 449 } 450 return GL_TRUE; 451 } 452 else { 453 /* with zooming */ 454 GLint row; 455 for (row=0; row<drawHeight; row++) { 456 ASSERT(drawWidth < MAX_WIDTH); 457 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); 458 span.x = destX; 459 span.y = destY; 460 span.end = drawWidth; 461 _mesa_write_zoomed_rgba_span(ctx, &span, 462 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0); 463 src += rowLength; 464 destY++; 465 } 466 return GL_TRUE; 467 } 468 } 469 else if (ctx->_ImageTransferState==0) { 470 /* write CI data to CI frame buffer */ 471 GLint row; 472 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 473 /* no zooming */ 474 for (row=0; row<drawHeight; row++) { 475 (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY, 476 src, NULL); 477 src += rowLength; 478 destY++; 479 } 480 return GL_TRUE; 481 } 482 else { 483 /* with zooming */ 484 return GL_FALSE; 485 } 486 } 487 } 488 else { 489 /* can't handle this pixel format and/or data type here */ 490 return GL_FALSE; 491 } 492 } 493 494 /* can't do a simple draw, have to use slow path */ 495 return GL_FALSE; 496} 497 498 499 500/* 501 * Draw color index image. 502 */ 503static void 504draw_index_pixels( GLcontext *ctx, GLint x, GLint y, 505 GLsizei width, GLsizei height, 506 GLenum type, const GLvoid *pixels ) 507{ 508 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 509 GLint row, skipPixels; 510 struct sw_span span; 511 512 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); 513 514 if (ctx->Depth.Test) 515 _mesa_span_default_z(ctx, &span); 516 if (ctx->Fog.Enabled) 517 _mesa_span_default_fog(ctx, &span); 518 519 /* 520 * General solution 521 */ 522 skipPixels = 0; 523 while (skipPixels < width) { 524 const GLint spanX = x + (zoom ? 0 : skipPixels); 525 GLint spanY = y; 526 const GLint spanEnd = (width - skipPixels > MAX_WIDTH) 527 ? MAX_WIDTH : (width - skipPixels); 528 ASSERT(spanEnd <= MAX_WIDTH); 529 for (row = 0; row < height; row++, span.y++) { 530 const GLvoid *source = _mesa_image_address(&ctx->Unpack, pixels, 531 width, height, 532 GL_COLOR_INDEX, type, 533 0, row, skipPixels); 534 _mesa_unpack_index_span(ctx, span.end, GL_UNSIGNED_INT, 535 span.array->index, type, source, &ctx->Unpack, 536 ctx->_ImageTransferState); 537 538 /* These may get changed during writing/clipping */ 539 span.x = spanX; 540 span.y = spanY; 541 span.end = spanEnd; 542 543 if (zoom) 544 _mesa_write_zoomed_index_span(ctx, &span, y, skipPixels); 545 else 546 _mesa_write_index_span(ctx, &span); 547 } 548 skipPixels += spanEnd; 549 } 550} 551 552 553 554/* 555 * Draw stencil image. 556 */ 557static void 558draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, 559 GLsizei width, GLsizei height, 560 GLenum type, const GLvoid *pixels ) 561{ 562 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 563 const GLint desty = y; 564 GLint row, skipPixels; 565 566 if (type != GL_BYTE && 567 type != GL_UNSIGNED_BYTE && 568 type != GL_SHORT && 569 type != GL_UNSIGNED_SHORT && 570 type != GL_INT && 571 type != GL_UNSIGNED_INT && 572 type != GL_FLOAT && 573 type != GL_BITMAP) { 574 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); 575 return; 576 } 577 578 if (ctx->Visual.stencilBits == 0) { 579 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)"); 580 return; 581 } 582 583 /* if width > MAX_WIDTH, have to process image in chunks */ 584 skipPixels = 0; 585 while (skipPixels < width) { 586 const GLint spanX = x; 587 GLint spanY = y; 588 const GLint spanWidth = (width - skipPixels > MAX_WIDTH) 589 ? MAX_WIDTH : (width - skipPixels); 590 591 for (row = 0; row < height; row++, spanY++) { 592 GLstencil values[MAX_WIDTH]; 593 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) 594 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; 595 const GLvoid *source = _mesa_image_address(&ctx->Unpack, pixels, 596 width, height, 597 GL_COLOR_INDEX, type, 598 0, row, skipPixels); 599 _mesa_unpack_index_span(ctx, spanWidth, destType, values, 600 type, source, &ctx->Unpack, 601 ctx->_ImageTransferState); 602 if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { 603 _mesa_shift_and_offset_stencil(ctx, spanWidth, values); 604 } 605 if (ctx->Pixel.MapStencilFlag) { 606 _mesa_map_stencil(ctx, spanWidth, values); 607 } 608 609 if (zoom) { 610 _mesa_write_zoomed_stencil_span(ctx, (GLuint) spanWidth, 611 spanX, spanY, values, desty, 0); 612 } 613 else { 614 _mesa_write_stencil_span(ctx, (GLuint) spanWidth, 615 spanX, spanY, values); 616 } 617 } 618 skipPixels += spanWidth; 619 } 620} 621 622 623/* 624 * Draw depth image. 625 */ 626static void 627draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, 628 GLsizei width, GLsizei height, 629 GLenum type, const GLvoid *pixels ) 630{ 631 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; 632 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 633 const GLint desty = y; 634 struct sw_span span; 635 636 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); 637 638 if (type != GL_BYTE 639 && type != GL_UNSIGNED_BYTE 640 && type != GL_SHORT 641 && type != GL_UNSIGNED_SHORT 642 && type != GL_INT 643 && type != GL_UNSIGNED_INT 644 && type != GL_FLOAT) { 645 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); 646 return; 647 } 648 649 _mesa_span_default_color(ctx, &span); 650 651 if (ctx->Fog.Enabled) 652 _mesa_span_default_fog(ctx, &span); 653 if (ctx->Texture._EnabledUnits) 654 _mesa_span_default_texcoords(ctx, &span); 655 656 if (type == GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16 657 && !bias_or_scale && !zoom && ctx->Visual.rgbMode 658 && width < MAX_WIDTH) { 659 /* Special case: directly write 16-bit depth values */ 660 GLint row; 661 span.x = x; 662 span.y = y; 663 span.end = width; 664 for (row = 0; row < height; row++, span.y++) { 665 const GLushort *zptr = (const GLushort *) 666 _mesa_image_address(&ctx->Unpack, pixels, width, height, 667 GL_DEPTH_COMPONENT, type, 0, row, 0); 668 GLint i; 669 for (i = 0; i < width; i++) 670 span.array->z[i] = zptr[i]; 671 _mesa_write_rgba_span(ctx, &span); 672 } 673 } 674 else if (type == GL_UNSIGNED_INT && ctx->Visual.depthBits == 32 675 && !bias_or_scale && !zoom && ctx->Visual.rgbMode 676 && width < MAX_WIDTH) { 677 /* Special case: directly write 32-bit depth values */ 678 GLint row; 679 span.x = x; 680 span.y = y; 681 span.end = width; 682 for (row = 0; row < height; row++, span.y++) { 683 const GLuint *zptr = (const GLuint *) 684 _mesa_image_address(&ctx->Unpack, pixels, width, height, 685 GL_DEPTH_COMPONENT, type, 0, row, 0); 686 MEMCPY(span.array->z, zptr, width * sizeof(GLdepth)); 687 _mesa_write_rgba_span(ctx, &span); 688 } 689 } 690 else { 691 /* General case */ 692 GLint row, skipPixels = 0; 693 694 /* in case width > MAX_WIDTH do the copy in chunks */ 695 while (skipPixels < width) { 696 const GLint spanX = x + (zoom ? 0 : skipPixels); 697 GLint spanY = y; 698 const GLint spanEnd = (width - skipPixels > MAX_WIDTH) 699 ? MAX_WIDTH : (width - skipPixels); 700 ASSERT(span.end <= MAX_WIDTH); 701 for (row = 0; row < height; row++, spanY++) { 702 GLfloat floatSpan[MAX_WIDTH]; 703 const GLvoid *src = _mesa_image_address(&ctx->Unpack, 704 pixels, width, height, 705 GL_DEPTH_COMPONENT, type, 706 0, row, skipPixels); 707 708 /* Set these for each row since the _mesa_write_* function may 709 * change them while clipping. 710 */ 711 span.x = spanX; 712 span.y = spanY; 713 span.end = spanEnd; 714 715 _mesa_unpack_depth_span(ctx, span.end, floatSpan, type, 716 src, &ctx->Unpack); 717 /* clamp depth values to [0,1] and convert from floats to ints */ 718 { 719 const GLfloat zs = ctx->DepthMaxF; 720 GLuint i; 721 for (i = 0; i < span.end; i++) { 722 span.array->z[i] = (GLdepth) (floatSpan[i] * zs + 0.5F); 723 } 724 } 725 if (ctx->Visual.rgbMode) { 726 if (zoom) { 727 _mesa_write_zoomed_rgba_span(ctx, &span, 728 (const GLchan (*)[4]) span.array->rgba, 729 desty, skipPixels); 730 } 731 else 732 _mesa_write_rgba_span(ctx, &span); 733 } 734 else { 735 if (zoom) 736 _mesa_write_zoomed_index_span(ctx, &span, desty, 0); 737 else 738 _mesa_write_index_span(ctx, &span); 739 } 740 } 741 skipPixels += spanEnd; 742 } 743 } 744} 745 746 747 748/* 749 * Draw RGBA image. 750 */ 751static void 752draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y, 753 GLsizei width, GLsizei height, 754 GLenum format, GLenum type, const GLvoid *pixels ) 755{ 756 SWcontext *swrast = SWRAST_CONTEXT(ctx); 757 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 758 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 759 const GLint desty = y; 760 GLboolean quickDraw; 761 GLfloat *convImage = NULL; 762 GLuint transferOps = ctx->_ImageTransferState; 763 struct sw_span span; 764 765 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 766 767 if (!_mesa_is_legal_format_and_type(format, type)) { 768 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)"); 769 return; 770 } 771 772 /* Try an optimized glDrawPixels first */ 773 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels)) 774 return; 775 776 if (ctx->Depth.Test) 777 _mesa_span_default_z(ctx, &span); 778 if (ctx->Fog.Enabled) 779 _mesa_span_default_fog(ctx, &span); 780 if (ctx->Texture._EnabledUnits) 781 _mesa_span_default_texcoords(ctx, &span); 782 783 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0 784 && x + width <= (GLint) ctx->DrawBuffer->Width 785 && y + height <= (GLint) ctx->DrawBuffer->Height) { 786 quickDraw = GL_TRUE; 787 } 788 else { 789 quickDraw = GL_FALSE; 790 } 791 792 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 793 /* Convolution has to be handled specially. We'll create an 794 * intermediate image, applying all pixel transfer operations 795 * up to convolution. Then we'll convolve the image. Then 796 * we'll proceed with the rest of the transfer operations and 797 * rasterize the image. 798 */ 799 GLint row; 800 GLfloat *dest, *tmpImage; 801 802 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 803 if (!tmpImage) { 804 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 805 return; 806 } 807 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 808 if (!convImage) { 809 FREE(tmpImage); 810 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 811 return; 812 } 813 814 /* Unpack the image and apply transfer ops up to convolution */ 815 dest = tmpImage; 816 for (row = 0; row < height; row++) { 817 const GLvoid *source = _mesa_image_address(unpack, 818 pixels, width, height, format, type, 0, row, 0); 819 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest, 820 format, type, source, unpack, 821 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 822 GL_FALSE); 823 dest += width * 4; 824 } 825 826 /* do convolution */ 827 if (ctx->Pixel.Convolution2DEnabled) { 828 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 829 } 830 else { 831 ASSERT(ctx->Pixel.Separable2DEnabled); 832 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 833 } 834 FREE(tmpImage); 835 836 /* continue transfer ops and draw the convolved image */ 837 unpack = &_mesa_native_packing; 838 pixels = convImage; 839 format = GL_RGBA; 840 type = GL_FLOAT; 841 transferOps &= IMAGE_POST_CONVOLUTION_BITS; 842 } 843 844 /* 845 * General solution 846 */ 847 { 848 const GLuint interpMask = span.interpMask; 849 const GLuint arrayMask = span.arrayMask; 850 GLint row, skipPixels = 0; 851 852 /* if the span is wider than MAX_WIDTH we have to do it in chunks */ 853 while (skipPixels < width) { 854 const GLint spanX = x + (zoom ? 0 : skipPixels); 855 GLint spanY = y; 856 const GLint spanEnd = (width - skipPixels > MAX_WIDTH) 857 ? MAX_WIDTH : (width - skipPixels); 858 ASSERT(span.end <= MAX_WIDTH); 859 860 for (row = 0; row < height; row++, spanY++) { 861 const GLvoid *source = _mesa_image_address(unpack, 862 pixels, width, height, format, type, 0, row, skipPixels); 863 864 /* Set these for each row since the _mesa_write_* function may 865 * change them while clipping. 866 */ 867 span.x = spanX; 868 span.y = spanY; 869 span.end = spanEnd; 870 span.arrayMask = arrayMask; 871 span.interpMask = interpMask; 872 873 _mesa_unpack_chan_color_span(ctx, span.end, GL_RGBA, 874 (GLchan *) span.array->rgba, 875 format, type, source, unpack, 876 transferOps); 877 878 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) || 879 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink)) 880 continue; 881 882 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { 883 _swrast_pixel_texture(ctx, &span); 884 } 885 886 /* draw the span */ 887 if (quickDraw) { 888 (*swrast->Driver.WriteRGBASpan)(ctx, span.end, span.x, span.y, 889 (CONST GLchan (*)[4]) span.array->rgba, NULL); 890 } 891 else if (zoom) { 892 _mesa_write_zoomed_rgba_span(ctx, &span, 893 (CONST GLchan (*)[4]) span.array->rgba, desty, skipPixels); 894 } 895 else { 896 _mesa_write_rgba_span(ctx, &span); 897 } 898 } 899 900 skipPixels += spanEnd; 901 } 902 } 903 904 if (convImage) { 905 FREE(convImage); 906 } 907} 908 909 910 911/* 912 * Execute glDrawPixels 913 */ 914void 915_swrast_DrawPixels( GLcontext *ctx, 916 GLint x, GLint y, 917 GLsizei width, GLsizei height, 918 GLenum format, GLenum type, 919 const struct gl_pixelstore_attrib *unpack, 920 const GLvoid *pixels ) 921{ 922 SWcontext *swrast = SWRAST_CONTEXT(ctx); 923 (void) unpack; 924 925 if (swrast->NewState) 926 _swrast_validate_derived( ctx ); 927 928 RENDER_START(swrast,ctx); 929 930 switch (format) { 931 case GL_STENCIL_INDEX: 932 draw_stencil_pixels( ctx, x, y, width, height, type, pixels ); 933 break; 934 case GL_DEPTH_COMPONENT: 935 draw_depth_pixels( ctx, x, y, width, height, type, pixels ); 936 break; 937 case GL_COLOR_INDEX: 938 if (ctx->Visual.rgbMode) 939 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels); 940 else 941 draw_index_pixels(ctx, x, y, width, height, type, pixels); 942 break; 943 case GL_RED: 944 case GL_GREEN: 945 case GL_BLUE: 946 case GL_ALPHA: 947 case GL_LUMINANCE: 948 case GL_LUMINANCE_ALPHA: 949 case GL_RGB: 950 case GL_BGR: 951 case GL_RGBA: 952 case GL_BGRA: 953 case GL_ABGR_EXT: 954 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels); 955 break; 956 default: 957 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" ); 958 } 959 960 RENDER_FINISH(swrast,ctx); 961} 962 963 964 965#if 0 /* experimental */ 966/* 967 * Execute glDrawDepthPixelsMESA(). 968 */ 969void 970_swrast_DrawDepthPixelsMESA( GLcontext *ctx, 971 GLint x, GLint y, 972 GLsizei width, GLsizei height, 973 GLenum colorFormat, GLenum colorType, 974 const GLvoid *colors, 975 GLenum depthType, const GLvoid *depths, 976 const struct gl_pixelstore_attrib *unpack ) 977{ 978 SWcontext *swrast = SWRAST_CONTEXT(ctx); 979 (void) unpack; 980 981 if (swrast->NewState) 982 _swrast_validate_derived( ctx ); 983 984 RENDER_START(swrast,ctx); 985 986 switch (colorFormat) { 987 case GL_COLOR_INDEX: 988 if (ctx->Visual.rgbMode) 989 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType, colors); 990 else 991 draw_index_pixels(ctx, x, y, width, height, colorType, colors); 992 break; 993 case GL_RED: 994 case GL_GREEN: 995 case GL_BLUE: 996 case GL_ALPHA: 997 case GL_LUMINANCE: 998 case GL_LUMINANCE_ALPHA: 999 case GL_RGB: 1000 case GL_BGR: 1001 case GL_RGBA: 1002 case GL_BGRA: 1003 case GL_ABGR_EXT: 1004 draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType, colors); 1005 break; 1006 default: 1007 _mesa_error( ctx, GL_INVALID_ENUM, 1008 "glDrawDepthPixelsMESA(colorFormat)" ); 1009 } 1010 1011 RENDER_FINISH(swrast,ctx); 1012} 1013#endif 1014