Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / swrast / s_blit.c
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)                 \
40 static void                                             \
41 NAME(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  */
95 RESAMPLE(resample_row_1, GLubyte, 1)
96 RESAMPLE(resample_row_2, GLushort, 1)
97 RESAMPLE(resample_row_4, GLuint, 1)
98 RESAMPLE(resample_row_8, GLuint, 2)
99 RESAMPLE(resample_row_16, GLuint, 4)
100
101
102 /**
103  * Blit color, depth or stencil with GL_NEAREST filtering.
104  */
105 static void
106 blit_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
246 static INLINE GLfloat
247 lerp_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  */
260 static void
261 resample_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  */
318 static void
319 blit_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  */
457 static void
458 simple_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  */
558 void
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 (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
572                         &dstX0, &dstY0, &dstX1, &dstY1)) {
573       return;
574    }
575
576    swrast_render_start(ctx);
577
578    if (srcX1 - srcX0 == dstX1 - dstX0 &&
579        srcY1 - srcY0 == dstY1 - dstY0 &&
580        srcX0 < srcX1 &&
581        srcY0 < srcY1 &&
582        dstX0 < dstX1 &&
583        dstY0 < dstY1) {
584       /* no stretching or flipping.
585        * filter doesn't matter.
586        */
587       for (i = 0; i < 3; i++) {
588          if (mask & buffers[i]) {
589             simple_blit(ctx, srcX0, srcY0, srcX1, srcY1,
590                         dstX0, dstY0, dstX1, dstY1, buffers[i]);
591          }
592       }
593    }
594    else {
595       if (filter == GL_NEAREST) {
596          for (i = 0; i < 3; i++) {
597             if (mask & buffers[i]) {
598                blit_nearest(ctx,  srcX0, srcY0, srcX1, srcY1,
599                             dstX0, dstY0, dstX1, dstY1, buffers[i]);
600             }
601          }
602       }
603       else {
604          ASSERT(filter == GL_LINEAR);
605          if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
606             blit_linear(ctx,  srcX0, srcY0, srcX1, srcY1,
607                         dstX0, dstY0, dstX1, dstY1);
608          }
609       }
610    }
611
612    swrast_render_finish(ctx);
613 }