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 gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 202 if (idx == BUFFER_NONE) 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, readFb->FlipY); 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 readFb->FlipY); 285 if (!srcMap) { 286 goto fail_no_memory; 287 } 288 ctx->Driver.MapRenderbuffer(ctx, drawRb, 289 dstXpos, dstYpos, 290 dstWidth, dstHeight, 291 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 292 drawFb->FlipY); 293 if (!dstMap) { 294 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 295 goto fail_no_memory; 296 } 297 } 298 299 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 300 GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 301 GLint srcRow = IROUND(srcRowF); 302 GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; 303 304 assert(srcRow >= 0); 305 assert(srcRow < srcHeight); 306 307 if (invertY) { 308 srcRow = srcHeight - 1 - srcRow; 309 } 310 311 /* get pixel row from source and resample to match dest width */ 312 if (prevY != srcRow) { 313 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; 314 315 switch (mode) { 316 case DIRECT: 317 memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); 318 break; 319 case UNPACK_RGBA_FLOAT: 320 _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, 321 srcBuffer); 322 break; 323 case UNPACK_Z_FLOAT: 324 _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, 325 srcBuffer); 326 break; 327 case UNPACK_Z_INT: 328 _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, 329 srcBuffer); 330 break; 331 case UNPACK_S: 332 _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, 333 srcRowStart, srcBuffer); 334 break; 335 } 336 337 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); 338 prevY = srcRow; 339 } 340 341 /* store pixel row in destination */ 342 switch (mode) { 343 case DIRECT: 344 memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth); 345 break; 346 case UNPACK_RGBA_FLOAT: 347 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, 348 dstRowStart); 349 break; 350 case UNPACK_Z_FLOAT: 351 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, 352 dstRowStart); 353 break; 354 case UNPACK_Z_INT: 355 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, 356 dstRowStart); 357 break; 358 case UNPACK_S: 359 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, 360 dstRowStart); 361 break; 362 } 363 } 364 365 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 366 if (drawRb != readRb) { 367 ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 368 } 369 } 370 371fail: 372 free(srcBuffer); 373 free(dstBuffer); 374 return; 375 376fail_no_memory: 377 free(srcBuffer); 378 free(dstBuffer); 379 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer"); 380} 381 382 383 384#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 385 386static inline GLfloat 387lerp_2d(GLfloat a, GLfloat b, 388 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 389{ 390 const GLfloat temp0 = LERP(a, v00, v10); 391 const GLfloat temp1 = LERP(a, v01, v11); 392 return LERP(b, temp0, temp1); 393} 394 395 396/** 397 * Bilinear interpolation of two source rows. 398 * GLubyte pixels. 399 */ 400static void 401resample_linear_row_ub(GLint srcWidth, GLint dstWidth, 402 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 403 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 404{ 405 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; 406 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; 407 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; 408 GLint dstCol; 409 410 for (dstCol = 0; dstCol < dstWidth; dstCol++) { 411 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 412 GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); 413 GLint srcCol1 = srcCol0 + 1; 414 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 415 GLfloat red, green, blue, alpha; 416 417 assert(srcCol0 < srcWidth); 418 assert(srcCol1 <= srcWidth); 419 420 if (srcCol1 == srcWidth) { 421 /* last column fudge */ 422 srcCol1--; 423 colWeight = 0.0; 424 } 425 426 if (flip) { 427 srcCol0 = srcWidth - 1 - srcCol0; 428 srcCol1 = srcWidth - 1 - srcCol1; 429 } 430 431 red = lerp_2d(colWeight, rowWeight, 432 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 433 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 434 green = lerp_2d(colWeight, rowWeight, 435 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 436 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 437 blue = lerp_2d(colWeight, rowWeight, 438 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 439 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 440 alpha = lerp_2d(colWeight, rowWeight, 441 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 442 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 443 444 dstColor[dstCol][RCOMP] = IFLOOR(red); 445 dstColor[dstCol][GCOMP] = IFLOOR(green); 446 dstColor[dstCol][BCOMP] = IFLOOR(blue); 447 dstColor[dstCol][ACOMP] = IFLOOR(alpha); 448 } 449} 450 451 452/** 453 * Bilinear interpolation of two source rows. floating point pixels. 454 */ 455static void 456resample_linear_row_float(GLint srcWidth, GLint dstWidth, 457 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 458 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 459{ 460 const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; 461 const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; 462 GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; 463 GLint dstCol; 464 465 for (dstCol = 0; dstCol < dstWidth; dstCol++) { 466 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 467 GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); 468 GLint srcCol1 = srcCol0 + 1; 469 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 470 GLfloat red, green, blue, alpha; 471 472 assert(srcCol0 < srcWidth); 473 assert(srcCol1 <= srcWidth); 474 475 if (srcCol1 == srcWidth) { 476 /* last column fudge */ 477 srcCol1--; 478 colWeight = 0.0; 479 } 480 481 if (flip) { 482 srcCol0 = srcWidth - 1 - srcCol0; 483 srcCol1 = srcWidth - 1 - srcCol1; 484 } 485 486 red = lerp_2d(colWeight, rowWeight, 487 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 488 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 489 green = lerp_2d(colWeight, rowWeight, 490 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 491 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 492 blue = lerp_2d(colWeight, rowWeight, 493 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 494 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 495 alpha = lerp_2d(colWeight, rowWeight, 496 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 497 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 498 499 dstColor[dstCol][RCOMP] = red; 500 dstColor[dstCol][GCOMP] = green; 501 dstColor[dstCol][BCOMP] = blue; 502 dstColor[dstCol][ACOMP] = alpha; 503 } 504} 505 506 507 508/** 509 * Bilinear filtered blit (color only, non-integer values). 510 */ 511static void 512blit_linear(struct gl_context *ctx, 513 struct gl_framebuffer *readFb, 514 struct gl_framebuffer *drawFb, 515 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 516 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 517{ 518 struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer; 519 struct gl_renderbuffer_attachment *readAtt = 520 &readFb->Attachment[readFb->_ColorReadBufferIndex]; 521 522 const GLint srcWidth = ABS(srcX1 - srcX0); 523 const GLint dstWidth = ABS(dstX1 - dstX0); 524 const GLint srcHeight = ABS(srcY1 - srcY0); 525 const GLint dstHeight = ABS(dstY1 - dstY0); 526 527 const GLint srcXpos = MIN2(srcX0, srcX1); 528 const GLint srcYpos = MIN2(srcY0, srcY1); 529 const GLint dstXpos = MIN2(dstX0, dstX1); 530 const GLint dstYpos = MIN2(dstY0, dstY1); 531 532 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 533 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 534 535 GLint dstRow; 536 537 GLint pixelSize; 538 GLvoid *srcBuffer0, *srcBuffer1; 539 GLint srcBufferY0 = -1, srcBufferY1 = -1; 540 GLvoid *dstBuffer; 541 542 mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); 543 GLuint bpp = _mesa_get_format_bytes(readFormat); 544 545 GLenum pixelType; 546 547 GLubyte *srcMap, *dstMap; 548 GLint srcRowStride, dstRowStride; 549 GLuint i; 550 551 552 /* Determine datatype for resampling */ 553 if (_mesa_get_format_max_bits(readFormat) == 8 && 554 _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { 555 pixelType = GL_UNSIGNED_BYTE; 556 pixelSize = 4 * sizeof(GLubyte); 557 } 558 else { 559 pixelType = GL_FLOAT; 560 pixelSize = 4 * sizeof(GLfloat); 561 } 562 563 /* Allocate the src/dst row buffers. 564 * Keep two adjacent src rows around for bilinear sampling. 565 */ 566 srcBuffer0 = malloc(pixelSize * srcWidth); 567 srcBuffer1 = malloc(pixelSize * srcWidth); 568 dstBuffer = malloc(pixelSize * dstWidth); 569 if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) { 570 goto fail_no_memory; 571 } 572 573 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { 574 gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 575 struct gl_renderbuffer_attachment *drawAtt; 576 struct gl_renderbuffer *drawRb; 577 mesa_format drawFormat; 578 579 if (idx == BUFFER_NONE) 580 continue; 581 582 drawAtt = &drawFb->Attachment[idx]; 583 drawRb = drawAtt->Renderbuffer; 584 if (!drawRb) 585 continue; 586 587 drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); 588 589 /* 590 * Map src / dst renderbuffers 591 */ 592 if ((readRb == drawRb) || 593 (readAtt->Texture && drawAtt->Texture && 594 (readAtt->Texture == drawAtt->Texture))) { 595 /* map whole buffer for read/write */ 596 ctx->Driver.MapRenderbuffer(ctx, readRb, 597 0, 0, readRb->Width, readRb->Height, 598 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 599 &srcMap, &srcRowStride, 600 readFb->FlipY); 601 if (!srcMap) { 602 goto fail_no_memory; 603 } 604 605 dstMap = srcMap; 606 dstRowStride = srcRowStride; 607 } 608 else { 609 /* different src/dst buffers */ 610 /* XXX with a bit of work we could just map the regions to be 611 * read/written instead of the whole buffers. 612 */ 613 ctx->Driver.MapRenderbuffer(ctx, readRb, 614 0, 0, readRb->Width, readRb->Height, 615 GL_MAP_READ_BIT, &srcMap, &srcRowStride, 616 readFb->FlipY); 617 if (!srcMap) { 618 goto fail_no_memory; 619 } 620 ctx->Driver.MapRenderbuffer(ctx, drawRb, 621 0, 0, drawRb->Width, drawRb->Height, 622 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 623 drawFb->FlipY); 624 if (!dstMap) { 625 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 626 goto fail_no_memory; 627 } 628 } 629 630 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 631 const GLint dstY = dstYpos + dstRow; 632 GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 633 GLint srcRow0 = MAX2(0, IFLOOR(srcRow)); 634 GLint srcRow1 = srcRow0 + 1; 635 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ 636 637 if (srcRow1 == srcHeight) { 638 /* last row fudge */ 639 srcRow1 = srcRow0; 640 rowWeight = 0.0; 641 } 642 643 if (invertY) { 644 srcRow0 = srcHeight - 1 - srcRow0; 645 srcRow1 = srcHeight - 1 - srcRow1; 646 } 647 648 srcY0 = srcYpos + srcRow0; 649 srcY1 = srcYpos + srcRow1; 650 651 /* get the two source rows */ 652 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { 653 /* use same source row buffers again */ 654 } 655 else if (srcY0 == srcBufferY1) { 656 /* move buffer1 into buffer0 by swapping pointers */ 657 GLvoid *tmp = srcBuffer0; 658 srcBuffer0 = srcBuffer1; 659 srcBuffer1 = tmp; 660 /* get y1 row */ 661 { 662 GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 663 if (pixelType == GL_UNSIGNED_BYTE) { 664 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 665 src, srcBuffer1); 666 } 667 else { 668 _mesa_unpack_rgba_row(readFormat, srcWidth, 669 src, srcBuffer1); 670 } 671 } 672 srcBufferY0 = srcY0; 673 srcBufferY1 = srcY1; 674 } 675 else { 676 /* get both new rows */ 677 { 678 GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; 679 GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 680 if (pixelType == GL_UNSIGNED_BYTE) { 681 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 682 src0, srcBuffer0); 683 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 684 src1, srcBuffer1); 685 } 686 else { 687 _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); 688 _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); 689 } 690 } 691 srcBufferY0 = srcY0; 692 srcBufferY1 = srcY1; 693 } 694 695 if (pixelType == GL_UNSIGNED_BYTE) { 696 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 697 dstBuffer, invertX, rowWeight); 698 } 699 else { 700 resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 701 dstBuffer, invertX, rowWeight); 702 } 703 704 /* store pixel row in destination */ 705 { 706 GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; 707 if (pixelType == GL_UNSIGNED_BYTE) { 708 _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 709 } 710 else { 711 _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 712 } 713 } 714 } 715 716 ctx->Driver.UnmapRenderbuffer(ctx, readRb); 717 if (drawRb != readRb) { 718 ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 719 } 720 } 721 722 free(srcBuffer0); 723 free(srcBuffer1); 724 free(dstBuffer); 725 return; 726 727fail_no_memory: 728 free(srcBuffer0); 729 free(srcBuffer1); 730 free(dstBuffer); 731 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 732} 733 734 735 736/** 737 * Software fallback for glBlitFramebufferEXT(). 738 */ 739void 740_swrast_BlitFramebuffer(struct gl_context *ctx, 741 struct gl_framebuffer *readFb, 742 struct gl_framebuffer *drawFb, 743 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 744 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 745 GLbitfield mask, GLenum filter) 746{ 747 static const GLbitfield buffers[3] = { 748 GL_COLOR_BUFFER_BIT, 749 GL_DEPTH_BUFFER_BIT, 750 GL_STENCIL_BUFFER_BIT 751 }; 752 static const GLenum buffer_enums[3] = { 753 GL_COLOR, 754 GL_DEPTH, 755 GL_STENCIL, 756 }; 757 GLint i; 758 759 /* Page 679 of OpenGL 4.4 spec says: 760 * "Added BlitFramebuffer to commands affected by conditional rendering in 761 * section 10.10 (Bug 9562)." 762 */ 763 if (!_mesa_check_conditional_render(ctx)) 764 return; /* Do not blit */ 765 766 if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1, 767 &dstX0, &dstY0, &dstX1, &dstY1)) { 768 return; 769 } 770 771 if (SWRAST_CONTEXT(ctx)->NewState) 772 _swrast_validate_derived(ctx); 773 774 /* First, try covering whatever buffers possible using the fast 1:1 copy 775 * path. 776 */ 777 if (srcX1 - srcX0 == dstX1 - dstX0 && 778 srcY1 - srcY0 == dstY1 - dstY0 && 779 srcX0 < srcX1 && 780 srcY0 < srcY1 && 781 dstX0 < dstX1 && 782 dstY0 < dstY1) { 783 for (i = 0; i < 3; i++) { 784 if (mask & buffers[i]) { 785 if (swrast_fast_copy_pixels(ctx, 786 readFb, drawFb, 787 srcX0, srcY0, 788 srcX1 - srcX0, srcY1 - srcY0, 789 dstX0, dstY0, 790 buffer_enums[i])) { 791 mask &= ~buffers[i]; 792 } 793 } 794 } 795 796 if (!mask) 797 return; 798 } 799 800 if (filter == GL_NEAREST) { 801 for (i = 0; i < 3; i++) { 802 if (mask & buffers[i]) { 803 blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 804 dstX0, dstY0, dstX1, dstY1, buffers[i]); 805 } 806 } 807 } 808 else { 809 assert(filter == GL_LINEAR); 810 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ 811 blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 812 dstX0, dstY0, dstX1, dstY1); 813 } 814 } 815 816} 817