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