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