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