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