s_blit.c revision c0277d953975ddc232aa34a101955d8314c99b96
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 "s_context.h" 31 32 33#define ABS(X) ((X) < 0 ? -(X) : (X)) 34 35 36/** 37 * Generate a row resampler function for GL_NEAREST mode. 38 */ 39#define RESAMPLE(NAME, PIXELTYPE, SIZE) \ 40static void \ 41NAME(GLint srcWidth, GLint dstWidth, \ 42 const GLvoid *srcBuffer, GLvoid *dstBuffer, \ 43 GLboolean flip) \ 44{ \ 45 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\ 46 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \ 47 GLint dstCol; \ 48 \ 49 if (flip) { \ 50 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 51 GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 52 ASSERT(srcCol >= 0); \ 53 ASSERT(srcCol < srcWidth); \ 54 srcCol = srcWidth - 1 - srcCol; /* flip */ \ 55 if (SIZE == 1) { \ 56 dst[dstCol] = src[srcCol]; \ 57 } \ 58 else if (SIZE == 2) { \ 59 dst[dstCol*2+0] = src[srcCol*2+0]; \ 60 dst[dstCol*2+1] = src[srcCol*2+1]; \ 61 } \ 62 else if (SIZE == 4) { \ 63 dst[dstCol*4+0] = src[srcCol*4+0]; \ 64 dst[dstCol*4+1] = src[srcCol*4+1]; \ 65 dst[dstCol*4+2] = src[srcCol*4+2]; \ 66 dst[dstCol*4+3] = src[srcCol*4+3]; \ 67 } \ 68 } \ 69 } \ 70 else { \ 71 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 72 GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 73 ASSERT(srcCol >= 0); \ 74 ASSERT(srcCol < srcWidth); \ 75 if (SIZE == 1) { \ 76 dst[dstCol] = src[srcCol]; \ 77 } \ 78 else if (SIZE == 2) { \ 79 dst[dstCol*2+0] = src[srcCol*2+0]; \ 80 dst[dstCol*2+1] = src[srcCol*2+1]; \ 81 } \ 82 else if (SIZE == 4) { \ 83 dst[dstCol*4+0] = src[srcCol*4+0]; \ 84 dst[dstCol*4+1] = src[srcCol*4+1]; \ 85 dst[dstCol*4+2] = src[srcCol*4+2]; \ 86 dst[dstCol*4+3] = src[srcCol*4+3]; \ 87 } \ 88 } \ 89 } \ 90} 91 92/** 93 * Resamplers for 1, 2, 4, 8 and 16-byte pixels. 94 */ 95RESAMPLE(resample_row_1, GLubyte, 1) 96RESAMPLE(resample_row_2, GLushort, 1) 97RESAMPLE(resample_row_4, GLuint, 1) 98RESAMPLE(resample_row_8, GLuint, 2) 99RESAMPLE(resample_row_16, GLuint, 4) 100 101 102/** 103 * Blit color, depth or stencil with GL_NEAREST filtering. 104 */ 105static void 106blit_nearest(struct gl_context *ctx, 107 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 108 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 109 GLbitfield buffer) 110{ 111 struct gl_renderbuffer *readRb, *drawRb; 112 113 const GLint srcWidth = ABS(srcX1 - srcX0); 114 const GLint dstWidth = ABS(dstX1 - dstX0); 115 const GLint srcHeight = ABS(srcY1 - srcY0); 116 const GLint dstHeight = ABS(dstY1 - dstY0); 117 118 const GLint srcXpos = MIN2(srcX0, srcX1); 119 const GLint srcYpos = MIN2(srcY0, srcY1); 120 const GLint dstXpos = MIN2(dstX0, dstX1); 121 const GLint dstYpos = MIN2(dstY0, dstY1); 122 123 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 124 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 125 126 GLint dstRow; 127 128 GLint comps, pixelSize; 129 GLvoid *srcBuffer, *dstBuffer; 130 GLint prevY = -1; 131 132 typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, 133 const GLvoid *srcBuffer, GLvoid *dstBuffer, 134 GLboolean flip); 135 resample_func resampleRow; 136 137 switch (buffer) { 138 case GL_COLOR_BUFFER_BIT: 139 readRb = ctx->ReadBuffer->_ColorReadBuffer; 140 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 141 comps = 4; 142 break; 143 case GL_DEPTH_BUFFER_BIT: 144 readRb = ctx->ReadBuffer->_DepthBuffer; 145 drawRb = ctx->DrawBuffer->_DepthBuffer; 146 comps = 1; 147 break; 148 case GL_STENCIL_BUFFER_BIT: 149 readRb = ctx->ReadBuffer->_StencilBuffer; 150 drawRb = ctx->DrawBuffer->_StencilBuffer; 151 comps = 1; 152 break; 153 default: 154 _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); 155 return; 156 } 157 158 switch (readRb->DataType) { 159 case GL_UNSIGNED_BYTE: 160 pixelSize = comps * sizeof(GLubyte); 161 break; 162 case GL_UNSIGNED_SHORT: 163 pixelSize = comps * sizeof(GLushort); 164 break; 165 case GL_UNSIGNED_INT: 166 pixelSize = comps * sizeof(GLuint); 167 break; 168 case GL_FLOAT: 169 pixelSize = comps * sizeof(GLfloat); 170 break; 171 default: 172 _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest", 173 readRb->DataType); 174 return; 175 } 176 177 /* choose row resampler */ 178 switch (pixelSize) { 179 case 1: 180 resampleRow = resample_row_1; 181 break; 182 case 2: 183 resampleRow = resample_row_2; 184 break; 185 case 4: 186 resampleRow = resample_row_4; 187 break; 188 case 8: 189 resampleRow = resample_row_8; 190 break; 191 case 16: 192 resampleRow = resample_row_16; 193 break; 194 default: 195 _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", 196 pixelSize); 197 return; 198 } 199 200 /* allocate the src/dst row buffers */ 201 srcBuffer = malloc(pixelSize * srcWidth); 202 if (!srcBuffer) { 203 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 204 return; 205 } 206 dstBuffer = malloc(pixelSize * dstWidth); 207 if (!dstBuffer) { 208 free(srcBuffer); 209 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 210 return; 211 } 212 213 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 214 const GLint dstY = dstYpos + dstRow; 215 GLint srcRow = (dstRow * srcHeight) / dstHeight; 216 GLint srcY; 217 218 ASSERT(srcRow >= 0); 219 ASSERT(srcRow < srcHeight); 220 221 if (invertY) { 222 srcRow = srcHeight - 1 - srcRow; 223 } 224 225 srcY = srcYpos + srcRow; 226 227 /* get pixel row from source and resample to match dest width */ 228 if (prevY != srcY) { 229 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY, srcBuffer); 230 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); 231 prevY = srcY; 232 } 233 234 /* store pixel row in destination */ 235 drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); 236 } 237 238 free(srcBuffer); 239 free(dstBuffer); 240} 241 242 243 244#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 245 246static INLINE GLfloat 247lerp_2d(GLfloat a, GLfloat b, 248 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 249{ 250 const GLfloat temp0 = LERP(a, v00, v10); 251 const GLfloat temp1 = LERP(a, v01, v11); 252 return LERP(b, temp0, temp1); 253} 254 255 256/** 257 * Bilinear interpolation of two source rows. 258 * GLubyte pixels. 259 */ 260static void 261resample_linear_row_ub(GLint srcWidth, GLint dstWidth, 262 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 263 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 264{ 265 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; 266 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; 267 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; 268 const GLfloat dstWidthF = (GLfloat) dstWidth; 269 GLint dstCol; 270 271 for (dstCol = 0; dstCol < dstWidth; dstCol++) { 272 const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF; 273 GLint srcCol0 = IFLOOR(srcCol); 274 GLint srcCol1 = srcCol0 + 1; 275 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 276 GLfloat red, green, blue, alpha; 277 278 ASSERT(srcCol0 >= 0); 279 ASSERT(srcCol0 < srcWidth); 280 ASSERT(srcCol1 <= srcWidth); 281 282 if (srcCol1 == srcWidth) { 283 /* last column fudge */ 284 srcCol1--; 285 colWeight = 0.0; 286 } 287 288 if (flip) { 289 srcCol0 = srcWidth - 1 - srcCol0; 290 srcCol1 = srcWidth - 1 - srcCol1; 291 } 292 293 red = lerp_2d(colWeight, rowWeight, 294 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 295 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 296 green = lerp_2d(colWeight, rowWeight, 297 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 298 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 299 blue = lerp_2d(colWeight, rowWeight, 300 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 301 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 302 alpha = lerp_2d(colWeight, rowWeight, 303 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 304 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 305 306 dstColor[dstCol][RCOMP] = IFLOOR(red); 307 dstColor[dstCol][GCOMP] = IFLOOR(green); 308 dstColor[dstCol][BCOMP] = IFLOOR(blue); 309 dstColor[dstCol][ACOMP] = IFLOOR(alpha); 310 } 311} 312 313 314 315/** 316 * Bilinear filtered blit (color only). 317 */ 318static void 319blit_linear(struct gl_context *ctx, 320 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 321 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 322{ 323 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer; 324 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 325 326 const GLint srcWidth = ABS(srcX1 - srcX0); 327 const GLint dstWidth = ABS(dstX1 - dstX0); 328 const GLint srcHeight = ABS(srcY1 - srcY0); 329 const GLint dstHeight = ABS(dstY1 - dstY0); 330 const GLfloat dstHeightF = (GLfloat) dstHeight; 331 332 const GLint srcXpos = MIN2(srcX0, srcX1); 333 const GLint srcYpos = MIN2(srcY0, srcY1); 334 const GLint dstXpos = MIN2(dstX0, dstX1); 335 const GLint dstYpos = MIN2(dstY0, dstY1); 336 337 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 338 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 339 340 GLint dstRow; 341 342 GLint pixelSize; 343 GLvoid *srcBuffer0, *srcBuffer1; 344 GLint srcBufferY0 = -1, srcBufferY1 = -1; 345 GLvoid *dstBuffer; 346 347 switch (readRb->DataType) { 348 case GL_UNSIGNED_BYTE: 349 pixelSize = 4 * sizeof(GLubyte); 350 break; 351 case GL_UNSIGNED_SHORT: 352 pixelSize = 4 * sizeof(GLushort); 353 break; 354 case GL_UNSIGNED_INT: 355 pixelSize = 4 * sizeof(GLuint); 356 break; 357 case GL_FLOAT: 358 pixelSize = 4 * sizeof(GLfloat); 359 break; 360 default: 361 _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest", 362 readRb->DataType); 363 return; 364 } 365 366 /* Allocate the src/dst row buffers. 367 * Keep two adjacent src rows around for bilinear sampling. 368 */ 369 srcBuffer0 = malloc(pixelSize * srcWidth); 370 if (!srcBuffer0) { 371 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 372 return; 373 } 374 srcBuffer1 = malloc(pixelSize * srcWidth); 375 if (!srcBuffer1) { 376 free(srcBuffer0); 377 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 378 return; 379 } 380 dstBuffer = malloc(pixelSize * dstWidth); 381 if (!dstBuffer) { 382 free(srcBuffer0); 383 free(srcBuffer1); 384 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 385 return; 386 } 387 388 for (dstRow = 0; dstRow < dstHeight; dstRow++) { 389 const GLint dstY = dstYpos + dstRow; 390 const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF; 391 GLint srcRow0 = IFLOOR(srcRow); 392 GLint srcRow1 = srcRow0 + 1; 393 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ 394 395 ASSERT(srcRow >= 0); 396 ASSERT(srcRow < srcHeight); 397 398 if (srcRow1 == srcHeight) { 399 /* last row fudge */ 400 srcRow1 = srcRow0; 401 rowWeight = 0.0; 402 } 403 404 if (invertY) { 405 srcRow0 = srcHeight - 1 - srcRow0; 406 srcRow1 = srcHeight - 1 - srcRow1; 407 } 408 409 srcY0 = srcYpos + srcRow0; 410 srcY1 = srcYpos + srcRow1; 411 412 /* get the two source rows */ 413 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { 414 /* use same source row buffers again */ 415 } 416 else if (srcY0 == srcBufferY1) { 417 /* move buffer1 into buffer0 by swapping pointers */ 418 GLvoid *tmp = srcBuffer0; 419 srcBuffer0 = srcBuffer1; 420 srcBuffer1 = tmp; 421 /* get y1 row */ 422 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); 423 srcBufferY0 = srcY0; 424 srcBufferY1 = srcY1; 425 } 426 else { 427 /* get both new rows */ 428 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY0, srcBuffer0); 429 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); 430 srcBufferY0 = srcY0; 431 srcBufferY1 = srcY1; 432 } 433 434 if (readRb->DataType == GL_UNSIGNED_BYTE) { 435 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 436 dstBuffer, invertX, rowWeight); 437 } 438 else { 439 _mesa_problem(ctx, "Unsupported color channel type in sw blit"); 440 break; 441 } 442 443 /* store pixel row in destination */ 444 drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); 445 } 446 447 free(srcBuffer0); 448 free(srcBuffer1); 449 free(dstBuffer); 450} 451 452 453/** 454 * Simple case: Blit color, depth or stencil with no scaling or flipping. 455 * XXX we could easily support vertical flipping here. 456 */ 457static void 458simple_blit(struct gl_context *ctx, 459 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 460 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 461 GLbitfield buffer) 462{ 463 struct gl_renderbuffer *readRb, *drawRb; 464 const GLint width = srcX1 - srcX0; 465 const GLint height = srcY1 - srcY0; 466 GLint row, srcY, dstY, yStep; 467 GLint comps, bytesPerRow; 468 void *rowBuffer; 469 470 /* only one buffer */ 471 ASSERT(_mesa_bitcount(buffer) == 1); 472 /* no flipping checks */ 473 ASSERT(srcX0 < srcX1); 474 ASSERT(srcY0 < srcY1); 475 ASSERT(dstX0 < dstX1); 476 ASSERT(dstY0 < dstY1); 477 /* size checks */ 478 ASSERT(srcX1 - srcX0 == dstX1 - dstX0); 479 ASSERT(srcY1 - srcY0 == dstY1 - dstY0); 480 481 /* determine if copy should be bottom-to-top or top-to-bottom */ 482 if (srcY0 > dstY0) { 483 /* src above dst: copy bottom-to-top */ 484 yStep = 1; 485 srcY = srcY0; 486 dstY = dstY0; 487 } 488 else { 489 /* src below dst: copy top-to-bottom */ 490 yStep = -1; 491 srcY = srcY1 - 1; 492 dstY = dstY1 - 1; 493 } 494 495 switch (buffer) { 496 case GL_COLOR_BUFFER_BIT: 497 readRb = ctx->ReadBuffer->_ColorReadBuffer; 498 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 499 comps = 4; 500 break; 501 case GL_DEPTH_BUFFER_BIT: 502 readRb = ctx->ReadBuffer->_DepthBuffer; 503 drawRb = ctx->DrawBuffer->_DepthBuffer; 504 comps = 1; 505 break; 506 case GL_STENCIL_BUFFER_BIT: 507 readRb = ctx->ReadBuffer->_StencilBuffer; 508 drawRb = ctx->DrawBuffer->_StencilBuffer; 509 comps = 1; 510 break; 511 default: 512 _mesa_problem(ctx, "unexpected buffer in simple_blit()"); 513 return; 514 } 515 516 ASSERT(readRb->DataType == drawRb->DataType); 517 518 /* compute bytes per row */ 519 switch (readRb->DataType) { 520 case GL_UNSIGNED_BYTE: 521 bytesPerRow = comps * width * sizeof(GLubyte); 522 break; 523 case GL_UNSIGNED_SHORT: 524 bytesPerRow = comps * width * sizeof(GLushort); 525 break; 526 case GL_UNSIGNED_INT: 527 bytesPerRow = comps * width * sizeof(GLuint); 528 break; 529 case GL_FLOAT: 530 bytesPerRow = comps * width * sizeof(GLfloat); 531 break; 532 default: 533 _mesa_problem(ctx, "unexpected buffer type in simple_blit"); 534 return; 535 } 536 537 /* allocate the row buffer */ 538 rowBuffer = malloc(bytesPerRow); 539 if (!rowBuffer) { 540 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 541 return; 542 } 543 544 for (row = 0; row < height; row++) { 545 readRb->GetRow(ctx, readRb, width, srcX0, srcY, rowBuffer); 546 drawRb->PutRow(ctx, drawRb, width, dstX0, dstY, rowBuffer, NULL); 547 srcY += yStep; 548 dstY += yStep; 549 } 550 551 free(rowBuffer); 552} 553 554 555/** 556 * Software fallback for glBlitFramebufferEXT(). 557 */ 558void 559_swrast_BlitFramebuffer(struct gl_context *ctx, 560 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 561 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 562 GLbitfield mask, GLenum filter) 563{ 564 static const GLbitfield buffers[3] = { 565 GL_COLOR_BUFFER_BIT, 566 GL_DEPTH_BUFFER_BIT, 567 GL_STENCIL_BUFFER_BIT 568 }; 569 GLint i; 570 571 if (!ctx->DrawBuffer->_NumColorDrawBuffers) 572 return; 573 574 if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, 575 &dstX0, &dstY0, &dstX1, &dstY1)) { 576 return; 577 } 578 579 swrast_render_start(ctx); 580 581 if (srcX1 - srcX0 == dstX1 - dstX0 && 582 srcY1 - srcY0 == dstY1 - dstY0 && 583 srcX0 < srcX1 && 584 srcY0 < srcY1 && 585 dstX0 < dstX1 && 586 dstY0 < dstY1) { 587 /* no stretching or flipping. 588 * filter doesn't matter. 589 */ 590 for (i = 0; i < 3; i++) { 591 if (mask & buffers[i]) { 592 simple_blit(ctx, srcX0, srcY0, srcX1, srcY1, 593 dstX0, dstY0, dstX1, dstY1, buffers[i]); 594 } 595 } 596 } 597 else { 598 if (filter == GL_NEAREST) { 599 for (i = 0; i < 3; i++) { 600 if (mask & buffers[i]) { 601 blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1, 602 dstX0, dstY0, dstX1, dstY1, buffers[i]); 603 } 604 } 605 } 606 else { 607 ASSERT(filter == GL_LINEAR); 608 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ 609 blit_linear(ctx, srcX0, srcY0, srcX1, srcY1, 610 dstX0, dstY0, dstX1, dstY1); 611 } 612 } 613 } 614 615 swrast_render_finish(ctx); 616} 617