1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "main/glheader.h" 27#include "main/condrender.h" 28#include "main/image.h" 29#include "main/macros.h" 30#include "main/format_unpack.h" 31#include "main/format_pack.h" 32#include "s_context.h" 33 34 35#define ABS(X) ((X) < 0 ? -(X) : (X)) 36 37 38/** 39 * Generate a row resampler function for GL_NEAREST mode. 40 */ 41#define RESAMPLE(NAME, PIXELTYPE, SIZE) \ 42static void \ 43NAME(GLint srcWidth, GLint dstWidth, \ 44 const GLvoid *srcBuffer, GLvoid *dstBuffer, \ 45 GLboolean flip) \ 46{ \ 47 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\ 48 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \ 49 GLint dstCol; \ 50 \ 51 if (flip) { \ 52 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 53 GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 54 ASSERT(srcCol >= 0); \ 55 ASSERT(srcCol < srcWidth); \ 56 srcCol = srcWidth - 1 - srcCol; /* flip */ \ 57 if (SIZE == 1) { \ 58 dst[dstCol] = src[srcCol]; \ 59 } \ 60 else if (SIZE == 2) { \ 61 dst[dstCol*2+0] = src[srcCol*2+0]; \ 62 dst[dstCol*2+1] = src[srcCol*2+1]; \ 63 } \ 64 else if (SIZE == 4) { \ 65 dst[dstCol*4+0] = src[srcCol*4+0]; \ 66 dst[dstCol*4+1] = src[srcCol*4+1]; \ 67 dst[dstCol*4+2] = src[srcCol*4+2]; \ 68 dst[dstCol*4+3] = src[srcCol*4+3]; \ 69 } \ 70 } \ 71 } \ 72 else { \ 73 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 74 GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 75 ASSERT(srcCol >= 0); \ 76 ASSERT(srcCol < srcWidth); \ 77 if (SIZE == 1) { \ 78 dst[dstCol] = src[srcCol]; \ 79 } \ 80 else if (SIZE == 2) { \ 81 dst[dstCol*2+0] = src[srcCol*2+0]; \ 82 dst[dstCol*2+1] = src[srcCol*2+1]; \ 83 } \ 84 else if (SIZE == 4) { \ 85 dst[dstCol*4+0] = src[srcCol*4+0]; \ 86 dst[dstCol*4+1] = src[srcCol*4+1]; \ 87 dst[dstCol*4+2] = src[srcCol*4+2]; \ 88 dst[dstCol*4+3] = src[srcCol*4+3]; \ 89 } \ 90 } \ 91 } \ 92} 93 94/** 95 * Resamplers for 1, 2, 4, 8 and 16-byte pixels. 96 */ 97RESAMPLE(resample_row_1, GLubyte, 1) 98RESAMPLE(resample_row_2, GLushort, 1) 99RESAMPLE(resample_row_4, GLuint, 1) 100RESAMPLE(resample_row_8, GLuint, 2) 101RESAMPLE(resample_row_16, GLuint, 4) 102 103 104/** 105 * Blit color, depth or stencil with GL_NEAREST filtering. 106 */ 107static void 108blit_nearest(struct gl_context *ctx, 109 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 110 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 111 GLbitfield buffer) 112{ 113 struct gl_renderbuffer *readRb, *drawRb; 114 115 const GLint srcWidth = ABS(srcX1 - srcX0); 116 const GLint dstWidth = ABS(dstX1 - dstX0); 117 const GLint srcHeight = ABS(srcY1 - srcY0); 118 const GLint dstHeight = ABS(dstY1 - dstY0); 119 120 const GLint srcXpos = MIN2(srcX0, srcX1); 121 const GLint srcYpos = MIN2(srcY0, srcY1); 122 const GLint dstXpos = MIN2(dstX0, dstX1); 123 const GLint dstYpos = MIN2(dstY0, dstY1); 124 125 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 126 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 127 enum mode { 128 DIRECT, 129 UNPACK_RGBA_FLOAT, 130 UNPACK_Z_FLOAT, 131 UNPACK_Z_INT, 132 UNPACK_S, 133 } mode; 134 GLubyte *srcMap, *dstMap; 135 GLint srcRowStride, dstRowStride; 136 GLint dstRow; 137 138 GLint pixelSize; 139 GLvoid *srcBuffer, *dstBuffer; 140 GLint prevY = -1; 141 142 typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, 143 const GLvoid *srcBuffer, GLvoid *dstBuffer, 144 GLboolean flip); 145 resample_func resampleRow; 146 147 switch (buffer) { 148 case GL_COLOR_BUFFER_BIT: 149 readRb = ctx->ReadBuffer->_ColorReadBuffer; 150 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 151 152 if (readRb->Format == drawRb->Format) { 153 mode = DIRECT; 154 pixelSize = _mesa_get_format_bytes(readRb->Format); 155 } else { 156 mode = UNPACK_RGBA_FLOAT; 157 pixelSize = 16; 158 } 159 160 break; 161 case GL_DEPTH_BUFFER_BIT: 162 readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; 163 drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; 164 165 /* Note that for depth/stencil, the formats of src/dst must match. By 166 * using the core helpers for pack/unpack, we avoid needing to handle 167 * masking for things like DEPTH copies of Z24S8. 168 */ 169 if (readRb->Format == MESA_FORMAT_Z32_FLOAT || 170 readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) { 171 mode = UNPACK_Z_FLOAT; 172 } else { 173 mode = UNPACK_Z_INT; 174 } 175 pixelSize = 4; 176 break; 177 case GL_STENCIL_BUFFER_BIT: 178 readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; 179 drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; 180 mode = UNPACK_S; 181 pixelSize = 1; 182 break; 183 default: 184 _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); 185 return; 186 } 187 188 /* choose row resampler */ 189 switch (pixelSize) { 190 case 1: 191 resampleRow = resample_row_1; 192 break; 193 case 2: 194 resampleRow = resample_row_2; 195 break; 196 case 4: 197 resampleRow = resample_row_4; 198 break; 199 case 8: 200 resampleRow = resample_row_8; 201 break; 202 case 16: 203 resampleRow = resample_row_16; 204 break; 205 default: 206 _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", 207 pixelSize); 208 return; 209 } 210 211 if (readRb == drawRb) { 212 /* map whole buffer for read/write */ 213 /* XXX we could be clever and just map the union region of the 214 * source and dest rects. 215 */ 216 GLubyte *map; 217 GLint rowStride; 218 GLint formatSize = _mesa_get_format_bytes(readRb->Format); 219 220 ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, 221 readRb->Width, readRb->Height, 222 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 223 &map, &rowStride); 224 if (!map) { 225 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 226 return; 227 } 228 229 srcMap = map + srcYpos * rowStride + srcXpos * formatSize; 230 dstMap = map + dstYpos * rowStride + dstXpos * formatSize; 231 232 /* this handles overlapping copies */ 233 if (srcY0 < dstY0) { 234 /* copy in reverse (top->down) order */ 235 srcMap += rowStride * (readRb->Height - 1); 236 dstMap += rowStride * (readRb->Height - 1); 237 srcRowStride = -rowStride; 238 dstRowStride = -rowStride; 239 } 240 else { 241 /* copy in normal (bottom->up) order */ 242 srcRowStride = rowStride; 243 dstRowStride = rowStride; 244 } 245 } 246 else { 247 /* different src/dst buffers */ 248 ctx->Driver.MapRenderbuffer(ctx, readRb, 249 srcXpos, srcYpos, 250 srcWidth, srcHeight, 251 GL_MAP_READ_BIT, &srcMap, &srcRowStride); 252 if (!srcMap) { 253 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 254 return; 255 } 256 ctx->Driver.MapRenderbuffer(ctx, drawRb, 257 dstXpos, dstYpos, 258 dstWidth, dstHeight, 259 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); 260 if (!dstMap) { 261 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 262 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 263 return; 264 } 265 } 266 267 /* allocate the src/dst row buffers */ 268 srcBuffer = malloc(pixelSize * srcWidth); 269 if (!srcBuffer) { 270 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 271 return; 272 } 273 dstBuffer = malloc(pixelSize * dstWidth); 274 if (!dstBuffer) { 275 free(srcBuffer); 276 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 277 return; 278 } 279 280 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 281 GLint srcRow = (dstRow * srcHeight) / dstHeight; 282 GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; 283 284 ASSERT(srcRow >= 0); 285 ASSERT(srcRow < srcHeight); 286 287 if (invertY) { 288 srcRow = srcHeight - 1 - srcRow; 289 } 290 291 /* get pixel row from source and resample to match dest width */ 292 if (prevY != srcRow) { 293 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; 294 295 switch (mode) { 296 case DIRECT: 297 memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); 298 break; 299 case UNPACK_RGBA_FLOAT: 300 _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, 301 srcBuffer); 302 break; 303 case UNPACK_Z_FLOAT: 304 _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, 305 srcBuffer); 306 break; 307 case UNPACK_Z_INT: 308 _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, 309 srcBuffer); 310 break; 311 case UNPACK_S: 312 _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, 313 srcRowStart, srcBuffer); 314 break; 315 } 316 317 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); 318 prevY = srcRow; 319 } 320 321 /* store pixel row in destination */ 322 switch (mode) { 323 case DIRECT: 324 memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth); 325 break; 326 case UNPACK_RGBA_FLOAT: 327 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, 328 dstRowStart); 329 break; 330 case UNPACK_Z_FLOAT: 331 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, 332 dstRowStart); 333 break; 334 case UNPACK_Z_INT: 335 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, 336 dstRowStart); 337 break; 338 case UNPACK_S: 339 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, 340 dstRowStart); 341 break; 342 } 343 } 344 345 free(srcBuffer); 346 free(dstBuffer); 347 348 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 349 if (drawRb != readRb) { 350 ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 351 } 352} 353 354 355 356#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 357 358static inline GLfloat 359lerp_2d(GLfloat a, GLfloat b, 360 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 361{ 362 const GLfloat temp0 = LERP(a, v00, v10); 363 const GLfloat temp1 = LERP(a, v01, v11); 364 return LERP(b, temp0, temp1); 365} 366 367 368/** 369 * Bilinear interpolation of two source rows. 370 * GLubyte pixels. 371 */ 372static void 373resample_linear_row_ub(GLint srcWidth, GLint dstWidth, 374 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 375 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 376{ 377 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; 378 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; 379 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; 380 const GLfloat dstWidthF = (GLfloat) dstWidth; 381 GLint dstCol; 382 383 for (dstCol = 0; dstCol < dstWidth; dstCol++) { 384 const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF; 385 GLint srcCol0 = IFLOOR(srcCol); 386 GLint srcCol1 = srcCol0 + 1; 387 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 388 GLfloat red, green, blue, alpha; 389 390 ASSERT(srcCol0 >= 0); 391 ASSERT(srcCol0 < srcWidth); 392 ASSERT(srcCol1 <= srcWidth); 393 394 if (srcCol1 == srcWidth) { 395 /* last column fudge */ 396 srcCol1--; 397 colWeight = 0.0; 398 } 399 400 if (flip) { 401 srcCol0 = srcWidth - 1 - srcCol0; 402 srcCol1 = srcWidth - 1 - srcCol1; 403 } 404 405 red = lerp_2d(colWeight, rowWeight, 406 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 407 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 408 green = lerp_2d(colWeight, rowWeight, 409 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 410 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 411 blue = lerp_2d(colWeight, rowWeight, 412 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 413 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 414 alpha = lerp_2d(colWeight, rowWeight, 415 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 416 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 417 418 dstColor[dstCol][RCOMP] = IFLOOR(red); 419 dstColor[dstCol][GCOMP] = IFLOOR(green); 420 dstColor[dstCol][BCOMP] = IFLOOR(blue); 421 dstColor[dstCol][ACOMP] = IFLOOR(alpha); 422 } 423} 424 425 426/** 427 * Bilinear interpolation of two source rows. floating point pixels. 428 */ 429static void 430resample_linear_row_float(GLint srcWidth, GLint dstWidth, 431 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 432 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 433{ 434 const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; 435 const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; 436 GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; 437 const GLfloat dstWidthF = (GLfloat) dstWidth; 438 GLint dstCol; 439 440 for (dstCol = 0; dstCol < dstWidth; dstCol++) { 441 const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF; 442 GLint srcCol0 = IFLOOR(srcCol); 443 GLint srcCol1 = srcCol0 + 1; 444 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 445 GLfloat red, green, blue, alpha; 446 447 ASSERT(srcCol0 >= 0); 448 ASSERT(srcCol0 < srcWidth); 449 ASSERT(srcCol1 <= srcWidth); 450 451 if (srcCol1 == srcWidth) { 452 /* last column fudge */ 453 srcCol1--; 454 colWeight = 0.0; 455 } 456 457 if (flip) { 458 srcCol0 = srcWidth - 1 - srcCol0; 459 srcCol1 = srcWidth - 1 - srcCol1; 460 } 461 462 red = lerp_2d(colWeight, rowWeight, 463 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 464 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 465 green = lerp_2d(colWeight, rowWeight, 466 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 467 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 468 blue = lerp_2d(colWeight, rowWeight, 469 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 470 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 471 alpha = lerp_2d(colWeight, rowWeight, 472 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 473 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 474 475 dstColor[dstCol][RCOMP] = red; 476 dstColor[dstCol][GCOMP] = green; 477 dstColor[dstCol][BCOMP] = blue; 478 dstColor[dstCol][ACOMP] = alpha; 479 } 480} 481 482 483 484/** 485 * Bilinear filtered blit (color only, non-integer values). 486 */ 487static void 488blit_linear(struct gl_context *ctx, 489 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 490 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 491{ 492 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer; 493 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 494 495 const GLint srcWidth = ABS(srcX1 - srcX0); 496 const GLint dstWidth = ABS(dstX1 - dstX0); 497 const GLint srcHeight = ABS(srcY1 - srcY0); 498 const GLint dstHeight = ABS(dstY1 - dstY0); 499 const GLfloat dstHeightF = (GLfloat) dstHeight; 500 501 const GLint srcXpos = MIN2(srcX0, srcX1); 502 const GLint srcYpos = MIN2(srcY0, srcY1); 503 const GLint dstXpos = MIN2(dstX0, dstX1); 504 const GLint dstYpos = MIN2(dstY0, dstY1); 505 506 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 507 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 508 509 GLint dstRow; 510 511 GLint pixelSize; 512 GLvoid *srcBuffer0, *srcBuffer1; 513 GLint srcBufferY0 = -1, srcBufferY1 = -1; 514 GLvoid *dstBuffer; 515 516 gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); 517 gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); 518 GLuint bpp = _mesa_get_format_bytes(readFormat); 519 520 GLenum pixelType; 521 522 GLubyte *srcMap, *dstMap; 523 GLint srcRowStride, dstRowStride; 524 525 526 /* Determine datatype for resampling */ 527 if (_mesa_get_format_max_bits(readFormat) == 8 && 528 _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { 529 pixelType = GL_UNSIGNED_BYTE; 530 pixelSize = 4 * sizeof(GLubyte); 531 } 532 else { 533 pixelType = GL_FLOAT; 534 pixelSize = 4 * sizeof(GLfloat); 535 } 536 537 /* Allocate the src/dst row buffers. 538 * Keep two adjacent src rows around for bilinear sampling. 539 */ 540 srcBuffer0 = malloc(pixelSize * srcWidth); 541 if (!srcBuffer0) { 542 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 543 return; 544 } 545 srcBuffer1 = malloc(pixelSize * srcWidth); 546 if (!srcBuffer1) { 547 free(srcBuffer0); 548 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 549 return; 550 } 551 dstBuffer = malloc(pixelSize * dstWidth); 552 if (!dstBuffer) { 553 free(srcBuffer0); 554 free(srcBuffer1); 555 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 556 return; 557 } 558 559 /* 560 * Map src / dst renderbuffers 561 */ 562 if (readRb == drawRb) { 563 /* map whole buffer for read/write */ 564 ctx->Driver.MapRenderbuffer(ctx, readRb, 565 0, 0, readRb->Width, readRb->Height, 566 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 567 &srcMap, &srcRowStride); 568 if (!srcMap) { 569 free(srcBuffer0); 570 free(srcBuffer1); 571 free(dstBuffer); 572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 573 return; 574 } 575 576 dstMap = srcMap; 577 dstRowStride = srcRowStride; 578 } 579 else { 580 /* different src/dst buffers */ 581 /* XXX with a bit of work we could just map the regions to be 582 * read/written instead of the whole buffers. 583 */ 584 ctx->Driver.MapRenderbuffer(ctx, readRb, 585 0, 0, readRb->Width, readRb->Height, 586 GL_MAP_READ_BIT, &srcMap, &srcRowStride); 587 if (!srcMap) { 588 free(srcBuffer0); 589 free(srcBuffer1); 590 free(dstBuffer); 591 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 592 return; 593 } 594 ctx->Driver.MapRenderbuffer(ctx, drawRb, 595 0, 0, drawRb->Width, drawRb->Height, 596 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); 597 if (!dstMap) { 598 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 599 free(srcBuffer0); 600 free(srcBuffer1); 601 free(dstBuffer); 602 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 603 return; 604 } 605 } 606 607 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 608 const GLint dstY = dstYpos + dstRow; 609 const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF; 610 GLint srcRow0 = IFLOOR(srcRow); 611 GLint srcRow1 = srcRow0 + 1; 612 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ 613 614 ASSERT(srcRow >= 0); 615 ASSERT(srcRow < srcHeight); 616 617 if (srcRow1 == srcHeight) { 618 /* last row fudge */ 619 srcRow1 = srcRow0; 620 rowWeight = 0.0; 621 } 622 623 if (invertY) { 624 srcRow0 = srcHeight - 1 - srcRow0; 625 srcRow1 = srcHeight - 1 - srcRow1; 626 } 627 628 srcY0 = srcYpos + srcRow0; 629 srcY1 = srcYpos + srcRow1; 630 631 /* get the two source rows */ 632 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { 633 /* use same source row buffers again */ 634 } 635 else if (srcY0 == srcBufferY1) { 636 /* move buffer1 into buffer0 by swapping pointers */ 637 GLvoid *tmp = srcBuffer0; 638 srcBuffer0 = srcBuffer1; 639 srcBuffer1 = tmp; 640 /* get y1 row */ 641 { 642 GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 643 if (pixelType == GL_UNSIGNED_BYTE) { 644 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 645 src, srcBuffer1); 646 } 647 else { 648 _mesa_unpack_rgba_row(readFormat, srcWidth, 649 src, srcBuffer1); 650 } 651 } 652 srcBufferY0 = srcY0; 653 srcBufferY1 = srcY1; 654 } 655 else { 656 /* get both new rows */ 657 { 658 GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; 659 GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 660 if (pixelType == GL_UNSIGNED_BYTE) { 661 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 662 src0, srcBuffer0); 663 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 664 src1, srcBuffer1); 665 } 666 else { 667 _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); 668 _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); 669 } 670 } 671 srcBufferY0 = srcY0; 672 srcBufferY1 = srcY1; 673 } 674 675 if (pixelType == GL_UNSIGNED_BYTE) { 676 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 677 dstBuffer, invertX, rowWeight); 678 } 679 else { 680 resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 681 dstBuffer, invertX, rowWeight); 682 } 683 684 /* store pixel row in destination */ 685 { 686 GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; 687 if (pixelType == GL_UNSIGNED_BYTE) { 688 _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 689 } 690 else { 691 _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 692 } 693 } 694 } 695 696 free(srcBuffer0); 697 free(srcBuffer1); 698 free(dstBuffer); 699 700 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 701 if (drawRb != readRb) { 702 ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 703 } 704} 705 706 707 708/** 709 * Software fallback for glBlitFramebufferEXT(). 710 */ 711void 712_swrast_BlitFramebuffer(struct gl_context *ctx, 713 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 714 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 715 GLbitfield mask, GLenum filter) 716{ 717 static const GLbitfield buffers[3] = { 718 GL_COLOR_BUFFER_BIT, 719 GL_DEPTH_BUFFER_BIT, 720 GL_STENCIL_BUFFER_BIT 721 }; 722 static const GLenum buffer_enums[3] = { 723 GL_COLOR, 724 GL_DEPTH, 725 GL_STENCIL, 726 }; 727 GLint i; 728 729 if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, 730 &dstX0, &dstY0, &dstX1, &dstY1)) { 731 return; 732 } 733 734 if (SWRAST_CONTEXT(ctx)->NewState) 735 _swrast_validate_derived(ctx); 736 737 /* First, try covering whatever buffers possible using the fast 1:1 copy 738 * path. 739 */ 740 if (srcX1 - srcX0 == dstX1 - dstX0 && 741 srcY1 - srcY0 == dstY1 - dstY0 && 742 srcX0 < srcX1 && 743 srcY0 < srcY1 && 744 dstX0 < dstX1 && 745 dstY0 < dstY1) { 746 for (i = 0; i < 3; i++) { 747 if (mask & buffers[i]) { 748 if (swrast_fast_copy_pixels(ctx, 749 srcX0, srcY0, 750 srcX1 - srcX0, srcY1 - srcY0, 751 dstX0, dstY0, 752 buffer_enums[i])) { 753 mask &= ~buffers[i]; 754 } 755 } 756 } 757 758 if (!mask) 759 return; 760 } 761 762 if (filter == GL_NEAREST) { 763 for (i = 0; i < 3; i++) { 764 if (mask & buffers[i]) { 765 blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1, 766 dstX0, dstY0, dstX1, dstY1, buffers[i]); 767 } 768 } 769 } 770 else { 771 ASSERT(filter == GL_LINEAR); 772 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ 773 blit_linear(ctx, srcX0, srcY0, srcX1, srcY1, 774 dstX0, dstY0, dstX1, dstY1); 775 } 776 } 777 778} 779