17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 47117f1b4Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 26c1f859d4Smrg#include "main/glheader.h" 27cdc920a0Smrg#include "main/condrender.h" 284a49301eSmrg#include "main/image.h" 29c1f859d4Smrg#include "main/macros.h" 30af69d88dSmrg#include "main/format_unpack.h" 31af69d88dSmrg#include "main/format_pack.h" 32af69d88dSmrg#include "main/condrender.h" 337117f1b4Smrg#include "s_context.h" 347117f1b4Smrg 357117f1b4Smrg 367117f1b4Smrg#define ABS(X) ((X) < 0 ? -(X) : (X)) 377117f1b4Smrg 387117f1b4Smrg 397117f1b4Smrg/** 407117f1b4Smrg * Generate a row resampler function for GL_NEAREST mode. 417117f1b4Smrg */ 427117f1b4Smrg#define RESAMPLE(NAME, PIXELTYPE, SIZE) \ 437117f1b4Smrgstatic void \ 447117f1b4SmrgNAME(GLint srcWidth, GLint dstWidth, \ 457117f1b4Smrg const GLvoid *srcBuffer, GLvoid *dstBuffer, \ 467117f1b4Smrg GLboolean flip) \ 477117f1b4Smrg{ \ 487117f1b4Smrg const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\ 497117f1b4Smrg PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \ 507117f1b4Smrg GLint dstCol; \ 517117f1b4Smrg \ 527117f1b4Smrg if (flip) { \ 537117f1b4Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 547117f1b4Smrg GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 5501e04c3fSmrg assert(srcCol >= 0); \ 5601e04c3fSmrg assert(srcCol < srcWidth); \ 577117f1b4Smrg srcCol = srcWidth - 1 - srcCol; /* flip */ \ 587117f1b4Smrg if (SIZE == 1) { \ 597117f1b4Smrg dst[dstCol] = src[srcCol]; \ 607117f1b4Smrg } \ 617117f1b4Smrg else if (SIZE == 2) { \ 627117f1b4Smrg dst[dstCol*2+0] = src[srcCol*2+0]; \ 637117f1b4Smrg dst[dstCol*2+1] = src[srcCol*2+1]; \ 647117f1b4Smrg } \ 657117f1b4Smrg else if (SIZE == 4) { \ 667117f1b4Smrg dst[dstCol*4+0] = src[srcCol*4+0]; \ 677117f1b4Smrg dst[dstCol*4+1] = src[srcCol*4+1]; \ 687117f1b4Smrg dst[dstCol*4+2] = src[srcCol*4+2]; \ 697117f1b4Smrg dst[dstCol*4+3] = src[srcCol*4+3]; \ 707117f1b4Smrg } \ 717117f1b4Smrg } \ 727117f1b4Smrg } \ 737117f1b4Smrg else { \ 747117f1b4Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 757117f1b4Smrg GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 7601e04c3fSmrg assert(srcCol >= 0); \ 7701e04c3fSmrg assert(srcCol < srcWidth); \ 787117f1b4Smrg if (SIZE == 1) { \ 797117f1b4Smrg dst[dstCol] = src[srcCol]; \ 807117f1b4Smrg } \ 817117f1b4Smrg else if (SIZE == 2) { \ 827117f1b4Smrg dst[dstCol*2+0] = src[srcCol*2+0]; \ 837117f1b4Smrg dst[dstCol*2+1] = src[srcCol*2+1]; \ 847117f1b4Smrg } \ 857117f1b4Smrg else if (SIZE == 4) { \ 867117f1b4Smrg dst[dstCol*4+0] = src[srcCol*4+0]; \ 877117f1b4Smrg dst[dstCol*4+1] = src[srcCol*4+1]; \ 887117f1b4Smrg dst[dstCol*4+2] = src[srcCol*4+2]; \ 897117f1b4Smrg dst[dstCol*4+3] = src[srcCol*4+3]; \ 907117f1b4Smrg } \ 917117f1b4Smrg } \ 927117f1b4Smrg } \ 937117f1b4Smrg} 947117f1b4Smrg 957117f1b4Smrg/** 967117f1b4Smrg * Resamplers for 1, 2, 4, 8 and 16-byte pixels. 977117f1b4Smrg */ 987117f1b4SmrgRESAMPLE(resample_row_1, GLubyte, 1) 997117f1b4SmrgRESAMPLE(resample_row_2, GLushort, 1) 1007117f1b4SmrgRESAMPLE(resample_row_4, GLuint, 1) 1017117f1b4SmrgRESAMPLE(resample_row_8, GLuint, 2) 1027117f1b4SmrgRESAMPLE(resample_row_16, GLuint, 4) 1037117f1b4Smrg 1047117f1b4Smrg 1057117f1b4Smrg/** 1067117f1b4Smrg * Blit color, depth or stencil with GL_NEAREST filtering. 1077117f1b4Smrg */ 1087117f1b4Smrgstatic void 1093464ebd5Sriastradhblit_nearest(struct gl_context *ctx, 11001e04c3fSmrg struct gl_framebuffer *readFb, 11101e04c3fSmrg struct gl_framebuffer *drawFb, 1127117f1b4Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 1137117f1b4Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 1144a49301eSmrg GLbitfield buffer) 1157117f1b4Smrg{ 116af69d88dSmrg struct gl_renderbuffer *readRb, *drawRb = NULL; 117af69d88dSmrg struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL; 118af69d88dSmrg GLuint numDrawBuffers = 0; 119af69d88dSmrg GLuint i; 1207117f1b4Smrg 1217117f1b4Smrg const GLint srcWidth = ABS(srcX1 - srcX0); 1227117f1b4Smrg const GLint dstWidth = ABS(dstX1 - dstX0); 1237117f1b4Smrg const GLint srcHeight = ABS(srcY1 - srcY0); 1247117f1b4Smrg const GLint dstHeight = ABS(dstY1 - dstY0); 1257117f1b4Smrg 1267117f1b4Smrg const GLint srcXpos = MIN2(srcX0, srcX1); 1277117f1b4Smrg const GLint srcYpos = MIN2(srcY0, srcY1); 1287117f1b4Smrg const GLint dstXpos = MIN2(dstX0, dstX1); 1297117f1b4Smrg const GLint dstYpos = MIN2(dstY0, dstY1); 1307117f1b4Smrg 1317117f1b4Smrg const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 1327117f1b4Smrg const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 133af69d88dSmrg enum mode { 134af69d88dSmrg DIRECT, 135af69d88dSmrg UNPACK_RGBA_FLOAT, 136af69d88dSmrg UNPACK_Z_FLOAT, 137af69d88dSmrg UNPACK_Z_INT, 138af69d88dSmrg UNPACK_S, 139af69d88dSmrg } mode = DIRECT; 140af69d88dSmrg GLubyte *srcMap, *dstMap; 141af69d88dSmrg GLint srcRowStride, dstRowStride; 1427117f1b4Smrg GLint dstRow; 1437117f1b4Smrg 144af69d88dSmrg GLint pixelSize = 0; 1457117f1b4Smrg GLvoid *srcBuffer, *dstBuffer; 1467117f1b4Smrg GLint prevY = -1; 1477117f1b4Smrg 1487117f1b4Smrg typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, 1497117f1b4Smrg const GLvoid *srcBuffer, GLvoid *dstBuffer, 1507117f1b4Smrg GLboolean flip); 1517117f1b4Smrg resample_func resampleRow; 1527117f1b4Smrg 1537117f1b4Smrg switch (buffer) { 1547117f1b4Smrg case GL_COLOR_BUFFER_BIT: 155af69d88dSmrg readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex]; 156af69d88dSmrg readRb = readFb->_ColorReadBuffer; 157af69d88dSmrg numDrawBuffers = drawFb->_NumColorDrawBuffers; 1587117f1b4Smrg break; 1597117f1b4Smrg case GL_DEPTH_BUFFER_BIT: 160af69d88dSmrg readAtt = &readFb->Attachment[BUFFER_DEPTH]; 161af69d88dSmrg drawAtt = &drawFb->Attachment[BUFFER_DEPTH]; 162af69d88dSmrg readRb = readAtt->Renderbuffer; 163af69d88dSmrg drawRb = drawAtt->Renderbuffer; 164af69d88dSmrg numDrawBuffers = 1; 165af69d88dSmrg 166af69d88dSmrg /* Note that for depth/stencil, the formats of src/dst must match. By 167af69d88dSmrg * using the core helpers for pack/unpack, we avoid needing to handle 168af69d88dSmrg * masking for things like DEPTH copies of Z24S8. 169af69d88dSmrg */ 170af69d88dSmrg if (readRb->Format == MESA_FORMAT_Z_FLOAT32 || 171af69d88dSmrg readRb->Format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { 172af69d88dSmrg mode = UNPACK_Z_FLOAT; 173af69d88dSmrg } else { 174af69d88dSmrg mode = UNPACK_Z_INT; 175af69d88dSmrg } 176af69d88dSmrg pixelSize = 4; 1777117f1b4Smrg break; 1787117f1b4Smrg case GL_STENCIL_BUFFER_BIT: 179af69d88dSmrg readAtt = &readFb->Attachment[BUFFER_STENCIL]; 180af69d88dSmrg drawAtt = &drawFb->Attachment[BUFFER_STENCIL]; 181af69d88dSmrg readRb = readAtt->Renderbuffer; 182af69d88dSmrg drawRb = drawAtt->Renderbuffer; 183af69d88dSmrg numDrawBuffers = 1; 184af69d88dSmrg mode = UNPACK_S; 185af69d88dSmrg pixelSize = 1; 1867117f1b4Smrg break; 1877117f1b4Smrg default: 1887117f1b4Smrg _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); 1897117f1b4Smrg return; 1907117f1b4Smrg } 1917117f1b4Smrg 1927117f1b4Smrg /* allocate the src/dst row buffers */ 193af69d88dSmrg srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth); 194af69d88dSmrg dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth); 195af69d88dSmrg if (!srcBuffer || !dstBuffer) 196af69d88dSmrg goto fail_no_memory; 197af69d88dSmrg 198af69d88dSmrg /* Blit to all the draw buffers */ 199af69d88dSmrg for (i = 0; i < numDrawBuffers; i++) { 200af69d88dSmrg if (buffer == GL_COLOR_BUFFER_BIT) { 20101e04c3fSmrg gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 20201e04c3fSmrg if (idx == BUFFER_NONE) 203af69d88dSmrg continue; 204af69d88dSmrg drawAtt = &drawFb->Attachment[idx]; 205af69d88dSmrg drawRb = drawAtt->Renderbuffer; 206af69d88dSmrg 207af69d88dSmrg if (!drawRb) 208af69d88dSmrg continue; 209af69d88dSmrg 210af69d88dSmrg if (readRb->Format == drawRb->Format) { 211af69d88dSmrg mode = DIRECT; 212af69d88dSmrg pixelSize = _mesa_get_format_bytes(readRb->Format); 213af69d88dSmrg } else { 214af69d88dSmrg mode = UNPACK_RGBA_FLOAT; 215af69d88dSmrg pixelSize = 16; 216af69d88dSmrg } 217af69d88dSmrg } 218af69d88dSmrg 219af69d88dSmrg /* choose row resampler */ 220af69d88dSmrg switch (pixelSize) { 221af69d88dSmrg case 1: 222af69d88dSmrg resampleRow = resample_row_1; 223af69d88dSmrg break; 224af69d88dSmrg case 2: 225af69d88dSmrg resampleRow = resample_row_2; 226af69d88dSmrg break; 227af69d88dSmrg case 4: 228af69d88dSmrg resampleRow = resample_row_4; 229af69d88dSmrg break; 230af69d88dSmrg case 8: 231af69d88dSmrg resampleRow = resample_row_8; 232af69d88dSmrg break; 233af69d88dSmrg case 16: 234af69d88dSmrg resampleRow = resample_row_16; 235af69d88dSmrg break; 236af69d88dSmrg default: 237af69d88dSmrg _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", 238af69d88dSmrg pixelSize); 239af69d88dSmrg goto fail; 240af69d88dSmrg } 2417117f1b4Smrg 242af69d88dSmrg if ((readRb == drawRb) || 243af69d88dSmrg (readAtt->Texture && drawAtt->Texture && 244af69d88dSmrg (readAtt->Texture == drawAtt->Texture))) { 245af69d88dSmrg /* map whole buffer for read/write */ 246af69d88dSmrg /* XXX we could be clever and just map the union region of the 247af69d88dSmrg * source and dest rects. 248af69d88dSmrg */ 249af69d88dSmrg GLubyte *map; 250af69d88dSmrg GLint rowStride; 251af69d88dSmrg GLint formatSize = _mesa_get_format_bytes(readRb->Format); 252af69d88dSmrg 253af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, 254af69d88dSmrg readRb->Width, readRb->Height, 255af69d88dSmrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 25601e04c3fSmrg &map, &rowStride, readFb->FlipY); 257af69d88dSmrg if (!map) { 258af69d88dSmrg goto fail_no_memory; 259af69d88dSmrg } 2607117f1b4Smrg 261af69d88dSmrg srcMap = map + srcYpos * rowStride + srcXpos * formatSize; 262af69d88dSmrg dstMap = map + dstYpos * rowStride + dstXpos * formatSize; 2637117f1b4Smrg 264af69d88dSmrg /* this handles overlapping copies */ 265af69d88dSmrg if (srcY0 < dstY0) { 266af69d88dSmrg /* copy in reverse (top->down) order */ 267af69d88dSmrg srcMap += rowStride * (readRb->Height - 1); 268af69d88dSmrg dstMap += rowStride * (readRb->Height - 1); 269af69d88dSmrg srcRowStride = -rowStride; 270af69d88dSmrg dstRowStride = -rowStride; 271af69d88dSmrg } 272af69d88dSmrg else { 273af69d88dSmrg /* copy in normal (bottom->up) order */ 274af69d88dSmrg srcRowStride = rowStride; 275af69d88dSmrg dstRowStride = rowStride; 276af69d88dSmrg } 277af69d88dSmrg } 278af69d88dSmrg else { 279af69d88dSmrg /* different src/dst buffers */ 280af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, readRb, 281af69d88dSmrg srcXpos, srcYpos, 282af69d88dSmrg srcWidth, srcHeight, 28301e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &srcRowStride, 28401e04c3fSmrg readFb->FlipY); 285af69d88dSmrg if (!srcMap) { 286af69d88dSmrg goto fail_no_memory; 287af69d88dSmrg } 288af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, drawRb, 289af69d88dSmrg dstXpos, dstYpos, 290af69d88dSmrg dstWidth, dstHeight, 29101e04c3fSmrg GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 29201e04c3fSmrg drawFb->FlipY); 293af69d88dSmrg if (!dstMap) { 294af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 295af69d88dSmrg goto fail_no_memory; 296af69d88dSmrg } 2977117f1b4Smrg } 2987117f1b4Smrg 299af69d88dSmrg for (dstRow = 0; dstRow < dstHeight; dstRow++) { 300af69d88dSmrg GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 3017ec681f3Smrg GLint srcRow = lroundf(srcRowF); 302af69d88dSmrg GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; 303af69d88dSmrg 30401e04c3fSmrg assert(srcRow >= 0); 30501e04c3fSmrg assert(srcRow < srcHeight); 306af69d88dSmrg 307af69d88dSmrg if (invertY) { 308af69d88dSmrg srcRow = srcHeight - 1 - srcRow; 309af69d88dSmrg } 310af69d88dSmrg 311af69d88dSmrg /* get pixel row from source and resample to match dest width */ 312af69d88dSmrg if (prevY != srcRow) { 313af69d88dSmrg GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; 314af69d88dSmrg 315af69d88dSmrg switch (mode) { 316af69d88dSmrg case DIRECT: 317af69d88dSmrg memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); 318af69d88dSmrg break; 319af69d88dSmrg case UNPACK_RGBA_FLOAT: 320af69d88dSmrg _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, 321af69d88dSmrg srcBuffer); 322af69d88dSmrg break; 323af69d88dSmrg case UNPACK_Z_FLOAT: 324af69d88dSmrg _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, 325af69d88dSmrg srcBuffer); 326af69d88dSmrg break; 327af69d88dSmrg case UNPACK_Z_INT: 328af69d88dSmrg _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, 329af69d88dSmrg srcBuffer); 330af69d88dSmrg break; 331af69d88dSmrg case UNPACK_S: 332af69d88dSmrg _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, 333af69d88dSmrg srcRowStart, srcBuffer); 334af69d88dSmrg break; 335af69d88dSmrg } 336af69d88dSmrg 3377ec681f3Smrg resampleRow(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); 338af69d88dSmrg prevY = srcRow; 339af69d88dSmrg } 3407117f1b4Smrg 341af69d88dSmrg /* store pixel row in destination */ 342af69d88dSmrg switch (mode) { 343af69d88dSmrg case DIRECT: 344af69d88dSmrg memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth); 345af69d88dSmrg break; 346af69d88dSmrg case UNPACK_RGBA_FLOAT: 347af69d88dSmrg _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, 348af69d88dSmrg dstRowStart); 349af69d88dSmrg break; 350af69d88dSmrg case UNPACK_Z_FLOAT: 351af69d88dSmrg _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, 352af69d88dSmrg dstRowStart); 353af69d88dSmrg break; 354af69d88dSmrg case UNPACK_Z_INT: 355af69d88dSmrg _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, 356af69d88dSmrg dstRowStart); 357af69d88dSmrg break; 358af69d88dSmrg case UNPACK_S: 359af69d88dSmrg _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, 360af69d88dSmrg dstRowStart); 361af69d88dSmrg break; 362af69d88dSmrg } 3637117f1b4Smrg } 3647117f1b4Smrg 365af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 366af69d88dSmrg if (drawRb != readRb) { 367af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 368af69d88dSmrg } 3697117f1b4Smrg } 3707117f1b4Smrg 371af69d88dSmrgfail: 372cdc920a0Smrg free(srcBuffer); 373cdc920a0Smrg free(dstBuffer); 374af69d88dSmrg return; 375af69d88dSmrg 376af69d88dSmrgfail_no_memory: 377af69d88dSmrg free(srcBuffer); 378af69d88dSmrg free(dstBuffer); 379af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer"); 3807117f1b4Smrg} 3817117f1b4Smrg 3827117f1b4Smrg 3837117f1b4Smrg 3847117f1b4Smrg#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 3857117f1b4Smrg 386af69d88dSmrgstatic inline GLfloat 3877117f1b4Smrglerp_2d(GLfloat a, GLfloat b, 3887117f1b4Smrg GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 3897117f1b4Smrg{ 3907117f1b4Smrg const GLfloat temp0 = LERP(a, v00, v10); 3917117f1b4Smrg const GLfloat temp1 = LERP(a, v01, v11); 3927117f1b4Smrg return LERP(b, temp0, temp1); 3937117f1b4Smrg} 3947117f1b4Smrg 3957117f1b4Smrg 3967117f1b4Smrg/** 3977117f1b4Smrg * Bilinear interpolation of two source rows. 3987117f1b4Smrg * GLubyte pixels. 3997117f1b4Smrg */ 4007117f1b4Smrgstatic void 4017117f1b4Smrgresample_linear_row_ub(GLint srcWidth, GLint dstWidth, 4027117f1b4Smrg const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 4037117f1b4Smrg GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 4047117f1b4Smrg{ 4057117f1b4Smrg const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; 4067117f1b4Smrg const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; 4077117f1b4Smrg GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; 4087117f1b4Smrg GLint dstCol; 4097117f1b4Smrg 4107117f1b4Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { 411af69d88dSmrg const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 4127ec681f3Smrg GLint srcCol0 = MAX2(0, util_ifloor(srcCol)); 4137117f1b4Smrg GLint srcCol1 = srcCol0 + 1; 4147117f1b4Smrg GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 4157117f1b4Smrg GLfloat red, green, blue, alpha; 4167117f1b4Smrg 41701e04c3fSmrg assert(srcCol0 < srcWidth); 41801e04c3fSmrg assert(srcCol1 <= srcWidth); 4197117f1b4Smrg 4207117f1b4Smrg if (srcCol1 == srcWidth) { 4217117f1b4Smrg /* last column fudge */ 4227117f1b4Smrg srcCol1--; 4237117f1b4Smrg colWeight = 0.0; 4247117f1b4Smrg } 4257117f1b4Smrg 4267117f1b4Smrg if (flip) { 4277117f1b4Smrg srcCol0 = srcWidth - 1 - srcCol0; 4287117f1b4Smrg srcCol1 = srcWidth - 1 - srcCol1; 4297117f1b4Smrg } 4307117f1b4Smrg 4317117f1b4Smrg red = lerp_2d(colWeight, rowWeight, 4327117f1b4Smrg srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 4337117f1b4Smrg srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 4347117f1b4Smrg green = lerp_2d(colWeight, rowWeight, 4357117f1b4Smrg srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 4367117f1b4Smrg srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 4377117f1b4Smrg blue = lerp_2d(colWeight, rowWeight, 4387117f1b4Smrg srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 4397117f1b4Smrg srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 4407117f1b4Smrg alpha = lerp_2d(colWeight, rowWeight, 4417117f1b4Smrg srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 4427117f1b4Smrg srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 4437ec681f3Smrg 4447ec681f3Smrg dstColor[dstCol][RCOMP] = util_ifloor(red); 4457ec681f3Smrg dstColor[dstCol][GCOMP] = util_ifloor(green); 4467ec681f3Smrg dstColor[dstCol][BCOMP] = util_ifloor(blue); 4477ec681f3Smrg dstColor[dstCol][ACOMP] = util_ifloor(alpha); 4487117f1b4Smrg } 4497117f1b4Smrg} 4507117f1b4Smrg 4517117f1b4Smrg 452af69d88dSmrg/** 453af69d88dSmrg * Bilinear interpolation of two source rows. floating point pixels. 454af69d88dSmrg */ 455af69d88dSmrgstatic void 456af69d88dSmrgresample_linear_row_float(GLint srcWidth, GLint dstWidth, 457af69d88dSmrg const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 458af69d88dSmrg GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 459af69d88dSmrg{ 460af69d88dSmrg const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; 461af69d88dSmrg const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; 462af69d88dSmrg GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; 463af69d88dSmrg GLint dstCol; 464af69d88dSmrg 465af69d88dSmrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { 466af69d88dSmrg const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 4677ec681f3Smrg GLint srcCol0 = MAX2(0, util_ifloor(srcCol)); 468af69d88dSmrg GLint srcCol1 = srcCol0 + 1; 469af69d88dSmrg GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 470af69d88dSmrg GLfloat red, green, blue, alpha; 471af69d88dSmrg 47201e04c3fSmrg assert(srcCol0 < srcWidth); 47301e04c3fSmrg assert(srcCol1 <= srcWidth); 474af69d88dSmrg 475af69d88dSmrg if (srcCol1 == srcWidth) { 476af69d88dSmrg /* last column fudge */ 477af69d88dSmrg srcCol1--; 478af69d88dSmrg colWeight = 0.0; 479af69d88dSmrg } 480af69d88dSmrg 481af69d88dSmrg if (flip) { 482af69d88dSmrg srcCol0 = srcWidth - 1 - srcCol0; 483af69d88dSmrg srcCol1 = srcWidth - 1 - srcCol1; 484af69d88dSmrg } 485af69d88dSmrg 486af69d88dSmrg red = lerp_2d(colWeight, rowWeight, 487af69d88dSmrg srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 488af69d88dSmrg srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 489af69d88dSmrg green = lerp_2d(colWeight, rowWeight, 490af69d88dSmrg srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 491af69d88dSmrg srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 492af69d88dSmrg blue = lerp_2d(colWeight, rowWeight, 493af69d88dSmrg srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 494af69d88dSmrg srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 495af69d88dSmrg alpha = lerp_2d(colWeight, rowWeight, 496af69d88dSmrg srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 497af69d88dSmrg srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 4987ec681f3Smrg 499af69d88dSmrg dstColor[dstCol][RCOMP] = red; 500af69d88dSmrg dstColor[dstCol][GCOMP] = green; 501af69d88dSmrg dstColor[dstCol][BCOMP] = blue; 502af69d88dSmrg dstColor[dstCol][ACOMP] = alpha; 503af69d88dSmrg } 504af69d88dSmrg} 505af69d88dSmrg 506af69d88dSmrg 5077117f1b4Smrg 5087117f1b4Smrg/** 509af69d88dSmrg * Bilinear filtered blit (color only, non-integer values). 5107117f1b4Smrg */ 5117117f1b4Smrgstatic void 5123464ebd5Sriastradhblit_linear(struct gl_context *ctx, 51301e04c3fSmrg struct gl_framebuffer *readFb, 51401e04c3fSmrg struct gl_framebuffer *drawFb, 5157117f1b4Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 5167117f1b4Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 5177117f1b4Smrg{ 518af69d88dSmrg struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer; 519af69d88dSmrg struct gl_renderbuffer_attachment *readAtt = 520af69d88dSmrg &readFb->Attachment[readFb->_ColorReadBufferIndex]; 5217117f1b4Smrg 5227117f1b4Smrg const GLint srcWidth = ABS(srcX1 - srcX0); 5237117f1b4Smrg const GLint dstWidth = ABS(dstX1 - dstX0); 5247117f1b4Smrg const GLint srcHeight = ABS(srcY1 - srcY0); 5257117f1b4Smrg const GLint dstHeight = ABS(dstY1 - dstY0); 5267117f1b4Smrg 5277117f1b4Smrg const GLint srcXpos = MIN2(srcX0, srcX1); 5287117f1b4Smrg const GLint srcYpos = MIN2(srcY0, srcY1); 5297117f1b4Smrg const GLint dstXpos = MIN2(dstX0, dstX1); 5307117f1b4Smrg const GLint dstYpos = MIN2(dstY0, dstY1); 5317117f1b4Smrg 5327117f1b4Smrg const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 5337117f1b4Smrg const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 5347117f1b4Smrg 5357117f1b4Smrg GLint dstRow; 5367117f1b4Smrg 5377117f1b4Smrg GLint pixelSize; 5387117f1b4Smrg GLvoid *srcBuffer0, *srcBuffer1; 5397117f1b4Smrg GLint srcBufferY0 = -1, srcBufferY1 = -1; 5407117f1b4Smrg GLvoid *dstBuffer; 5417117f1b4Smrg 542af69d88dSmrg mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); 543af69d88dSmrg GLuint bpp = _mesa_get_format_bytes(readFormat); 544af69d88dSmrg 545af69d88dSmrg GLenum pixelType; 546af69d88dSmrg 547af69d88dSmrg GLubyte *srcMap, *dstMap; 548af69d88dSmrg GLint srcRowStride, dstRowStride; 549af69d88dSmrg GLuint i; 550af69d88dSmrg 551af69d88dSmrg 552af69d88dSmrg /* Determine datatype for resampling */ 553af69d88dSmrg if (_mesa_get_format_max_bits(readFormat) == 8 && 554af69d88dSmrg _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { 555af69d88dSmrg pixelType = GL_UNSIGNED_BYTE; 5567117f1b4Smrg pixelSize = 4 * sizeof(GLubyte); 557af69d88dSmrg } 558af69d88dSmrg else { 559af69d88dSmrg pixelType = GL_FLOAT; 5607117f1b4Smrg pixelSize = 4 * sizeof(GLfloat); 5617117f1b4Smrg } 5627117f1b4Smrg 5637117f1b4Smrg /* Allocate the src/dst row buffers. 5647117f1b4Smrg * Keep two adjacent src rows around for bilinear sampling. 5657117f1b4Smrg */ 566cdc920a0Smrg srcBuffer0 = malloc(pixelSize * srcWidth); 567cdc920a0Smrg srcBuffer1 = malloc(pixelSize * srcWidth); 568cdc920a0Smrg dstBuffer = malloc(pixelSize * dstWidth); 569af69d88dSmrg if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) { 570af69d88dSmrg goto fail_no_memory; 5717117f1b4Smrg } 5727117f1b4Smrg 573af69d88dSmrg for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { 57401e04c3fSmrg gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 575af69d88dSmrg struct gl_renderbuffer_attachment *drawAtt; 576af69d88dSmrg struct gl_renderbuffer *drawRb; 577af69d88dSmrg mesa_format drawFormat; 5787117f1b4Smrg 57901e04c3fSmrg if (idx == BUFFER_NONE) 580af69d88dSmrg continue; 5817117f1b4Smrg 582af69d88dSmrg drawAtt = &drawFb->Attachment[idx]; 583af69d88dSmrg drawRb = drawAtt->Renderbuffer; 584af69d88dSmrg if (!drawRb) 585af69d88dSmrg continue; 5867117f1b4Smrg 587af69d88dSmrg drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); 5887117f1b4Smrg 589af69d88dSmrg /* 590af69d88dSmrg * Map src / dst renderbuffers 591af69d88dSmrg */ 592af69d88dSmrg if ((readRb == drawRb) || 593af69d88dSmrg (readAtt->Texture && drawAtt->Texture && 594af69d88dSmrg (readAtt->Texture == drawAtt->Texture))) { 595af69d88dSmrg /* map whole buffer for read/write */ 596af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, readRb, 597af69d88dSmrg 0, 0, readRb->Width, readRb->Height, 598af69d88dSmrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 59901e04c3fSmrg &srcMap, &srcRowStride, 60001e04c3fSmrg readFb->FlipY); 601af69d88dSmrg if (!srcMap) { 602af69d88dSmrg goto fail_no_memory; 603af69d88dSmrg } 6047117f1b4Smrg 605af69d88dSmrg dstMap = srcMap; 606af69d88dSmrg dstRowStride = srcRowStride; 6077117f1b4Smrg } 6087117f1b4Smrg else { 609af69d88dSmrg /* different src/dst buffers */ 610af69d88dSmrg /* XXX with a bit of work we could just map the regions to be 611af69d88dSmrg * read/written instead of the whole buffers. 612af69d88dSmrg */ 613af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, readRb, 614af69d88dSmrg 0, 0, readRb->Width, readRb->Height, 61501e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &srcRowStride, 61601e04c3fSmrg readFb->FlipY); 617af69d88dSmrg if (!srcMap) { 618af69d88dSmrg goto fail_no_memory; 619af69d88dSmrg } 620af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, drawRb, 621af69d88dSmrg 0, 0, drawRb->Width, drawRb->Height, 62201e04c3fSmrg GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 62301e04c3fSmrg drawFb->FlipY); 624af69d88dSmrg if (!dstMap) { 625af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 626af69d88dSmrg goto fail_no_memory; 627af69d88dSmrg } 6287117f1b4Smrg } 6297117f1b4Smrg 630af69d88dSmrg for (dstRow = 0; dstRow < dstHeight; dstRow++) { 631af69d88dSmrg const GLint dstY = dstYpos + dstRow; 632af69d88dSmrg GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 6337ec681f3Smrg GLint srcRow0 = MAX2(0, util_ifloor(srcRow)); 634af69d88dSmrg GLint srcRow1 = srcRow0 + 1; 635af69d88dSmrg GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ 636af69d88dSmrg 637af69d88dSmrg if (srcRow1 == srcHeight) { 638af69d88dSmrg /* last row fudge */ 639af69d88dSmrg srcRow1 = srcRow0; 640af69d88dSmrg rowWeight = 0.0; 641af69d88dSmrg } 6427117f1b4Smrg 643af69d88dSmrg if (invertY) { 644af69d88dSmrg srcRow0 = srcHeight - 1 - srcRow0; 645af69d88dSmrg srcRow1 = srcHeight - 1 - srcRow1; 646af69d88dSmrg } 6477117f1b4Smrg 648af69d88dSmrg srcY0 = srcYpos + srcRow0; 649af69d88dSmrg srcY1 = srcYpos + srcRow1; 6507117f1b4Smrg 651af69d88dSmrg /* get the two source rows */ 652af69d88dSmrg if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { 653af69d88dSmrg /* use same source row buffers again */ 654af69d88dSmrg } 655af69d88dSmrg else if (srcY0 == srcBufferY1) { 656af69d88dSmrg /* move buffer1 into buffer0 by swapping pointers */ 657af69d88dSmrg GLvoid *tmp = srcBuffer0; 658af69d88dSmrg srcBuffer0 = srcBuffer1; 659af69d88dSmrg srcBuffer1 = tmp; 660af69d88dSmrg /* get y1 row */ 661af69d88dSmrg { 662af69d88dSmrg GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 663af69d88dSmrg if (pixelType == GL_UNSIGNED_BYTE) { 664af69d88dSmrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 665af69d88dSmrg src, srcBuffer1); 666af69d88dSmrg } 667af69d88dSmrg else { 668af69d88dSmrg _mesa_unpack_rgba_row(readFormat, srcWidth, 669af69d88dSmrg src, srcBuffer1); 670af69d88dSmrg } 671af69d88dSmrg } 672af69d88dSmrg srcBufferY0 = srcY0; 673af69d88dSmrg srcBufferY1 = srcY1; 674af69d88dSmrg } 675af69d88dSmrg else { 676af69d88dSmrg /* get both new rows */ 677af69d88dSmrg { 678af69d88dSmrg GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; 679af69d88dSmrg GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 680af69d88dSmrg if (pixelType == GL_UNSIGNED_BYTE) { 681af69d88dSmrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 682af69d88dSmrg src0, srcBuffer0); 683af69d88dSmrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 684af69d88dSmrg src1, srcBuffer1); 685af69d88dSmrg } 686af69d88dSmrg else { 687af69d88dSmrg _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); 688af69d88dSmrg _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); 689af69d88dSmrg } 690af69d88dSmrg } 691af69d88dSmrg srcBufferY0 = srcY0; 692af69d88dSmrg srcBufferY1 = srcY1; 693af69d88dSmrg } 6947117f1b4Smrg 695af69d88dSmrg if (pixelType == GL_UNSIGNED_BYTE) { 696af69d88dSmrg resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 697af69d88dSmrg dstBuffer, invertX, rowWeight); 698af69d88dSmrg } 699af69d88dSmrg else { 700af69d88dSmrg resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 701af69d88dSmrg dstBuffer, invertX, rowWeight); 702af69d88dSmrg } 7037117f1b4Smrg 704af69d88dSmrg /* store pixel row in destination */ 705af69d88dSmrg { 706af69d88dSmrg GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; 707af69d88dSmrg if (pixelType == GL_UNSIGNED_BYTE) { 708af69d88dSmrg _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 709af69d88dSmrg } 710af69d88dSmrg else { 711af69d88dSmrg _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 712af69d88dSmrg } 713af69d88dSmrg } 714af69d88dSmrg } 7157117f1b4Smrg 716af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 717af69d88dSmrg if (drawRb != readRb) { 718af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 719af69d88dSmrg } 7207117f1b4Smrg } 7217117f1b4Smrg 722af69d88dSmrg free(srcBuffer0); 723af69d88dSmrg free(srcBuffer1); 724af69d88dSmrg free(dstBuffer); 725af69d88dSmrg return; 7267117f1b4Smrg 727af69d88dSmrgfail_no_memory: 728af69d88dSmrg free(srcBuffer0); 729af69d88dSmrg free(srcBuffer1); 730af69d88dSmrg free(dstBuffer); 731af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 7327117f1b4Smrg} 7337117f1b4Smrg 7347117f1b4Smrg 735af69d88dSmrg 7367117f1b4Smrg/** 7377117f1b4Smrg * Software fallback for glBlitFramebufferEXT(). 7387117f1b4Smrg */ 7397117f1b4Smrgvoid 7403464ebd5Sriastradh_swrast_BlitFramebuffer(struct gl_context *ctx, 74101e04c3fSmrg struct gl_framebuffer *readFb, 74201e04c3fSmrg struct gl_framebuffer *drawFb, 7437117f1b4Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 7447117f1b4Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 7457117f1b4Smrg GLbitfield mask, GLenum filter) 7467117f1b4Smrg{ 7474a49301eSmrg static const GLbitfield buffers[3] = { 7487117f1b4Smrg GL_COLOR_BUFFER_BIT, 7497117f1b4Smrg GL_DEPTH_BUFFER_BIT, 7507117f1b4Smrg GL_STENCIL_BUFFER_BIT 7517117f1b4Smrg }; 752af69d88dSmrg static const GLenum buffer_enums[3] = { 753af69d88dSmrg GL_COLOR, 754af69d88dSmrg GL_DEPTH, 755af69d88dSmrg GL_STENCIL, 756af69d88dSmrg }; 7577117f1b4Smrg GLint i; 7587117f1b4Smrg 759af69d88dSmrg /* Page 679 of OpenGL 4.4 spec says: 760af69d88dSmrg * "Added BlitFramebuffer to commands affected by conditional rendering in 761af69d88dSmrg * section 10.10 (Bug 9562)." 762af69d88dSmrg */ 763af69d88dSmrg if (!_mesa_check_conditional_render(ctx)) 764af69d88dSmrg return; /* Do not blit */ 765af69d88dSmrg 76601e04c3fSmrg if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1, 7674a49301eSmrg &dstX0, &dstY0, &dstX1, &dstY1)) { 7687117f1b4Smrg return; 7697117f1b4Smrg } 7707117f1b4Smrg 771af69d88dSmrg if (SWRAST_CONTEXT(ctx)->NewState) 772af69d88dSmrg _swrast_validate_derived(ctx); 7737117f1b4Smrg 774af69d88dSmrg /* First, try covering whatever buffers possible using the fast 1:1 copy 775af69d88dSmrg * path. 776af69d88dSmrg */ 7777117f1b4Smrg if (srcX1 - srcX0 == dstX1 - dstX0 && 7787117f1b4Smrg srcY1 - srcY0 == dstY1 - dstY0 && 7797117f1b4Smrg srcX0 < srcX1 && 7807117f1b4Smrg srcY0 < srcY1 && 7817117f1b4Smrg dstX0 < dstX1 && 7827117f1b4Smrg dstY0 < dstY1) { 7837117f1b4Smrg for (i = 0; i < 3; i++) { 7847117f1b4Smrg if (mask & buffers[i]) { 78501e04c3fSmrg if (swrast_fast_copy_pixels(ctx, 78601e04c3fSmrg readFb, drawFb, 78701e04c3fSmrg srcX0, srcY0, 78801e04c3fSmrg srcX1 - srcX0, srcY1 - srcY0, 78901e04c3fSmrg dstX0, dstY0, 79001e04c3fSmrg buffer_enums[i])) { 79101e04c3fSmrg mask &= ~buffers[i]; 79201e04c3fSmrg } 79301e04c3fSmrg } 7947117f1b4Smrg } 795af69d88dSmrg 796af69d88dSmrg if (!mask) 79701e04c3fSmrg return; 7987117f1b4Smrg } 799af69d88dSmrg 800af69d88dSmrg if (filter == GL_NEAREST) { 801af69d88dSmrg for (i = 0; i < 3; i++) { 80201e04c3fSmrg if (mask & buffers[i]) { 80301e04c3fSmrg blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 80401e04c3fSmrg dstX0, dstY0, dstX1, dstY1, buffers[i]); 80501e04c3fSmrg } 8067117f1b4Smrg } 807af69d88dSmrg } 808af69d88dSmrg else { 80901e04c3fSmrg assert(filter == GL_LINEAR); 810af69d88dSmrg if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ 81101e04c3fSmrg blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 81201e04c3fSmrg dstX0, dstY0, dstX1, dstY1); 8137117f1b4Smrg } 8147117f1b4Smrg } 8157117f1b4Smrg 8167117f1b4Smrg} 817