OSDN Git Service

mesa: remove outdated version lines in comments
[android-x86/external-mesa.git] / src / mesa / swrast / s_blit.c
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * 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 "main/format_unpack.h"
31 #include "main/format_pack.h"
32 #include "s_context.h"
33
34
35 #define ABS(X)   ((X) < 0 ? -(X) : (X))
36
37
38 /**
39  * Generate a row resampler function for GL_NEAREST mode.
40  */
41 #define RESAMPLE(NAME, PIXELTYPE, SIZE)                 \
42 static void                                             \
43 NAME(GLint srcWidth, GLint dstWidth,                    \
44      const GLvoid *srcBuffer, GLvoid *dstBuffer,        \
45      GLboolean flip)                                    \
46 {                                                       \
47    const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
48    PIXELTYPE *dst = (PIXELTYPE *) dstBuffer;            \
49    GLint dstCol;                                        \
50                                                         \
51    if (flip) {                                          \
52       for (dstCol = 0; dstCol < dstWidth; dstCol++) {   \
53          GLint srcCol = (dstCol * srcWidth) / dstWidth; \
54          ASSERT(srcCol >= 0);                           \
55          ASSERT(srcCol < srcWidth);                     \
56          srcCol = srcWidth - 1 - srcCol; /* flip */     \
57          if (SIZE == 1) {                               \
58             dst[dstCol] = src[srcCol];                  \
59          }                                              \
60          else if (SIZE == 2) {                          \
61             dst[dstCol*2+0] = src[srcCol*2+0];          \
62             dst[dstCol*2+1] = src[srcCol*2+1];          \
63          }                                              \
64          else if (SIZE == 4) {                          \
65             dst[dstCol*4+0] = src[srcCol*4+0];          \
66             dst[dstCol*4+1] = src[srcCol*4+1];          \
67             dst[dstCol*4+2] = src[srcCol*4+2];          \
68             dst[dstCol*4+3] = src[srcCol*4+3];          \
69          }                                              \
70       }                                                 \
71    }                                                    \
72    else {                                               \
73       for (dstCol = 0; dstCol < dstWidth; dstCol++) {   \
74          GLint srcCol = (dstCol * srcWidth) / dstWidth; \
75          ASSERT(srcCol >= 0);                           \
76          ASSERT(srcCol < srcWidth);                     \
77          if (SIZE == 1) {                               \
78             dst[dstCol] = src[srcCol];                  \
79          }                                              \
80          else if (SIZE == 2) {                          \
81             dst[dstCol*2+0] = src[srcCol*2+0];          \
82             dst[dstCol*2+1] = src[srcCol*2+1];          \
83          }                                              \
84          else if (SIZE == 4) {                          \
85             dst[dstCol*4+0] = src[srcCol*4+0];          \
86             dst[dstCol*4+1] = src[srcCol*4+1];          \
87             dst[dstCol*4+2] = src[srcCol*4+2];          \
88             dst[dstCol*4+3] = src[srcCol*4+3];          \
89          }                                              \
90       }                                                 \
91    }                                                    \
92 }
93
94 /**
95  * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
96  */
97 RESAMPLE(resample_row_1, GLubyte, 1)
98 RESAMPLE(resample_row_2, GLushort, 1)
99 RESAMPLE(resample_row_4, GLuint, 1)
100 RESAMPLE(resample_row_8, GLuint, 2)
101 RESAMPLE(resample_row_16, GLuint, 4)
102
103
104 /**
105  * Blit color, depth or stencil with GL_NEAREST filtering.
106  */
107 static void
108 blit_nearest(struct gl_context *ctx,
109              GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
110              GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
111              GLbitfield buffer)
112 {
113    struct gl_renderbuffer *readRb, *drawRb = NULL;
114    struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL;
115    struct gl_framebuffer *readFb = ctx->ReadBuffer;
116    struct gl_framebuffer *drawFb = ctx->DrawBuffer;
117    GLuint numDrawBuffers = 0;
118    GLuint i;
119
120    const GLint srcWidth = ABS(srcX1 - srcX0);
121    const GLint dstWidth = ABS(dstX1 - dstX0);
122    const GLint srcHeight = ABS(srcY1 - srcY0);
123    const GLint dstHeight = ABS(dstY1 - dstY0);
124
125    const GLint srcXpos = MIN2(srcX0, srcX1);
126    const GLint srcYpos = MIN2(srcY0, srcY1);
127    const GLint dstXpos = MIN2(dstX0, dstX1);
128    const GLint dstYpos = MIN2(dstY0, dstY1);
129
130    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
131    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
132    enum mode {
133       DIRECT,
134       UNPACK_RGBA_FLOAT,
135       UNPACK_Z_FLOAT,
136       UNPACK_Z_INT,
137       UNPACK_S,
138    } mode = DIRECT;
139    GLubyte *srcMap, *dstMap;
140    GLint srcRowStride, dstRowStride;
141    GLint dstRow;
142
143    GLint pixelSize = 0;
144    GLvoid *srcBuffer, *dstBuffer;
145    GLint prevY = -1;
146
147    typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
148                                  const GLvoid *srcBuffer, GLvoid *dstBuffer,
149                                  GLboolean flip);
150    resample_func resampleRow;
151
152    switch (buffer) {
153    case GL_COLOR_BUFFER_BIT:
154       readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
155       readRb = readFb->_ColorReadBuffer;
156       numDrawBuffers = drawFb->_NumColorDrawBuffers;
157       break;
158    case GL_DEPTH_BUFFER_BIT:
159       readAtt = &readFb->Attachment[BUFFER_DEPTH];
160       drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
161       readRb = readAtt->Renderbuffer;
162       drawRb = drawAtt->Renderbuffer;
163       numDrawBuffers = 1;
164
165       /* Note that for depth/stencil, the formats of src/dst must match.  By
166        * using the core helpers for pack/unpack, we avoid needing to handle
167        * masking for things like DEPTH copies of Z24S8.
168        */
169       if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
170           readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
171          mode = UNPACK_Z_FLOAT;
172       } else {
173          mode = UNPACK_Z_INT;
174       }
175       pixelSize = 4;
176       break;
177    case GL_STENCIL_BUFFER_BIT:
178       readAtt = &readFb->Attachment[BUFFER_STENCIL];
179       drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
180       readRb = readAtt->Renderbuffer;
181       drawRb = drawAtt->Renderbuffer;
182       numDrawBuffers = 1;
183       mode = UNPACK_S;
184       pixelSize = 1;
185       break;
186    default:
187       _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
188       return;
189    }
190
191    /* allocate the src/dst row buffers */
192    srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth);
193    dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth);
194    if (!srcBuffer || !dstBuffer)
195       goto fail_no_memory;
196
197    /* Blit to all the draw buffers */
198    for (i = 0; i < numDrawBuffers; i++) {
199       if (buffer == GL_COLOR_BUFFER_BIT) {
200          int idx = drawFb->_ColorDrawBufferIndexes[i];
201          if (idx == -1)
202             continue;
203          drawAtt = &drawFb->Attachment[idx];
204          drawRb = drawAtt->Renderbuffer;
205
206          if (!drawRb)
207             continue;
208
209          if (readRb->Format == drawRb->Format) {
210             mode = DIRECT;
211             pixelSize = _mesa_get_format_bytes(readRb->Format);
212          } else {
213             mode = UNPACK_RGBA_FLOAT;
214             pixelSize = 16;
215          }
216       }
217
218       /* choose row resampler */
219       switch (pixelSize) {
220       case 1:
221          resampleRow = resample_row_1;
222          break;
223       case 2:
224          resampleRow = resample_row_2;
225          break;
226       case 4:
227          resampleRow = resample_row_4;
228          break;
229       case 8:
230          resampleRow = resample_row_8;
231          break;
232       case 16:
233          resampleRow = resample_row_16;
234          break;
235       default:
236          _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
237                        pixelSize);
238          goto fail;
239       }
240
241       if ((readRb == drawRb) ||
242           (readAtt->Texture && drawAtt->Texture &&
243            (readAtt->Texture == drawAtt->Texture))) {
244          /* map whole buffer for read/write */
245          /* XXX we could be clever and just map the union region of the
246           * source and dest rects.
247           */
248          GLubyte *map;
249          GLint rowStride;
250          GLint formatSize = _mesa_get_format_bytes(readRb->Format);
251
252          ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
253                                      readRb->Width, readRb->Height,
254                                      GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
255                                      &map, &rowStride);
256          if (!map) {
257             goto fail_no_memory;
258          }
259
260          srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
261          dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
262
263          /* this handles overlapping copies */
264          if (srcY0 < dstY0) {
265             /* copy in reverse (top->down) order */
266             srcMap += rowStride * (readRb->Height - 1);
267             dstMap += rowStride * (readRb->Height - 1);
268             srcRowStride = -rowStride;
269             dstRowStride = -rowStride;
270          }
271          else {
272             /* copy in normal (bottom->up) order */
273             srcRowStride = rowStride;
274             dstRowStride = rowStride;
275          }
276       }
277       else {
278          /* different src/dst buffers */
279          ctx->Driver.MapRenderbuffer(ctx, readRb,
280                                      srcXpos, srcYpos,
281                                      srcWidth, srcHeight,
282                                      GL_MAP_READ_BIT, &srcMap, &srcRowStride);
283          if (!srcMap) {
284             goto fail_no_memory;
285          }
286          ctx->Driver.MapRenderbuffer(ctx, drawRb,
287                                      dstXpos, dstYpos,
288                                      dstWidth, dstHeight,
289                                      GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
290          if (!dstMap) {
291             ctx->Driver.UnmapRenderbuffer(ctx, readRb);
292             goto fail_no_memory;
293          }
294       }
295
296       for (dstRow = 0; dstRow < dstHeight; dstRow++) {
297          GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
298          GLint srcRow = IROUND(srcRowF);
299          GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
300
301          ASSERT(srcRow >= 0);
302          ASSERT(srcRow < srcHeight);
303
304          if (invertY) {
305             srcRow = srcHeight - 1 - srcRow;
306          }
307
308          /* get pixel row from source and resample to match dest width */
309          if (prevY != srcRow) {
310             GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
311
312             switch (mode) {
313             case DIRECT:
314                memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
315                break;
316             case UNPACK_RGBA_FLOAT:
317                _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
318                                      srcBuffer);
319                break;
320             case UNPACK_Z_FLOAT:
321                _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
322                                         srcBuffer);
323                break;
324             case UNPACK_Z_INT:
325                _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
326                                        srcBuffer);
327                break;
328             case UNPACK_S:
329                _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
330                                               srcRowStart, srcBuffer);
331                break;
332             }
333
334             (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
335             prevY = srcRow;
336          }
337
338          /* store pixel row in destination */
339          switch (mode) {
340          case DIRECT:
341             memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
342             break;
343          case UNPACK_RGBA_FLOAT:
344             _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
345                                       dstRowStart);
346             break;
347          case UNPACK_Z_FLOAT:
348             _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
349                                    dstRowStart);
350             break;
351          case UNPACK_Z_INT:
352             _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
353                                   dstRowStart);
354             break;
355          case UNPACK_S:
356             _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
357                                          dstRowStart);
358             break;
359          }
360       }
361
362       ctx->Driver.UnmapRenderbuffer(ctx, readRb);
363       if (drawRb != readRb) {
364          ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
365       }
366    }
367
368 fail:
369    free(srcBuffer);
370    free(dstBuffer);
371    return;
372
373 fail_no_memory:
374    free(srcBuffer);
375    free(dstBuffer);
376    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
377 }
378
379
380
381 #define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
382
383 static inline GLfloat
384 lerp_2d(GLfloat a, GLfloat b,
385         GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
386 {
387    const GLfloat temp0 = LERP(a, v00, v10);
388    const GLfloat temp1 = LERP(a, v01, v11);
389    return LERP(b, temp0, temp1);
390 }
391
392
393 /**
394  * Bilinear interpolation of two source rows.
395  * GLubyte pixels.
396  */
397 static void
398 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
399                        const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
400                        GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
401 {
402    const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
403    const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
404    GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
405    GLint dstCol;
406
407    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
408       const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
409       GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
410       GLint srcCol1 = srcCol0 + 1;
411       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
412       GLfloat red, green, blue, alpha;
413
414       ASSERT(srcCol0 < srcWidth);
415       ASSERT(srcCol1 <= srcWidth);
416
417       if (srcCol1 == srcWidth) {
418          /* last column fudge */
419          srcCol1--;
420          colWeight = 0.0;
421       }
422
423       if (flip) {
424          srcCol0 = srcWidth - 1 - srcCol0;
425          srcCol1 = srcWidth - 1 - srcCol1;
426       }
427
428       red = lerp_2d(colWeight, rowWeight,
429                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
430                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
431       green = lerp_2d(colWeight, rowWeight,
432                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
433                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
434       blue = lerp_2d(colWeight, rowWeight,
435                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
436                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
437       alpha = lerp_2d(colWeight, rowWeight,
438                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
439                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
440       
441       dstColor[dstCol][RCOMP] = IFLOOR(red);
442       dstColor[dstCol][GCOMP] = IFLOOR(green);
443       dstColor[dstCol][BCOMP] = IFLOOR(blue);
444       dstColor[dstCol][ACOMP] = IFLOOR(alpha);
445    }
446 }
447
448
449 /**
450  * Bilinear interpolation of two source rows.  floating point pixels.
451  */
452 static void
453 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
454                           const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
455                           GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
456 {
457    const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
458    const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
459    GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
460    GLint dstCol;
461
462    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
463       const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
464       GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
465       GLint srcCol1 = srcCol0 + 1;
466       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
467       GLfloat red, green, blue, alpha;
468
469       ASSERT(srcCol0 < srcWidth);
470       ASSERT(srcCol1 <= srcWidth);
471
472       if (srcCol1 == srcWidth) {
473          /* last column fudge */
474          srcCol1--;
475          colWeight = 0.0;
476       }
477
478       if (flip) {
479          srcCol0 = srcWidth - 1 - srcCol0;
480          srcCol1 = srcWidth - 1 - srcCol1;
481       }
482
483       red = lerp_2d(colWeight, rowWeight,
484                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
485                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
486       green = lerp_2d(colWeight, rowWeight,
487                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
488                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
489       blue = lerp_2d(colWeight, rowWeight,
490                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
491                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
492       alpha = lerp_2d(colWeight, rowWeight,
493                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
494                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
495       
496       dstColor[dstCol][RCOMP] = red;
497       dstColor[dstCol][GCOMP] = green;
498       dstColor[dstCol][BCOMP] = blue;
499       dstColor[dstCol][ACOMP] = alpha;
500    }
501 }
502
503
504
505 /**
506  * Bilinear filtered blit (color only, non-integer values).
507  */
508 static void
509 blit_linear(struct gl_context *ctx,
510             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
511             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
512 {
513    struct gl_framebuffer *drawFb = ctx->DrawBuffer;
514    struct gl_framebuffer *readFb = ctx->ReadBuffer;
515    struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
516    struct gl_renderbuffer_attachment *readAtt =
517       &readFb->Attachment[readFb->_ColorReadBufferIndex];
518
519    const GLint srcWidth = ABS(srcX1 - srcX0);
520    const GLint dstWidth = ABS(dstX1 - dstX0);
521    const GLint srcHeight = ABS(srcY1 - srcY0);
522    const GLint dstHeight = ABS(dstY1 - dstY0);
523
524    const GLint srcXpos = MIN2(srcX0, srcX1);
525    const GLint srcYpos = MIN2(srcY0, srcY1);
526    const GLint dstXpos = MIN2(dstX0, dstX1);
527    const GLint dstYpos = MIN2(dstY0, dstY1);
528
529    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
530    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
531
532    GLint dstRow;
533
534    GLint pixelSize;
535    GLvoid *srcBuffer0, *srcBuffer1;
536    GLint srcBufferY0 = -1, srcBufferY1 = -1;
537    GLvoid *dstBuffer;
538
539    gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
540    GLuint bpp = _mesa_get_format_bytes(readFormat);
541
542    GLenum pixelType;
543
544    GLubyte *srcMap, *dstMap;
545    GLint srcRowStride, dstRowStride;
546    GLuint i;
547
548
549    /* Determine datatype for resampling */
550    if (_mesa_get_format_max_bits(readFormat) == 8 &&
551        _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
552       pixelType = GL_UNSIGNED_BYTE;
553       pixelSize = 4 * sizeof(GLubyte);
554    }
555    else {
556       pixelType = GL_FLOAT;
557       pixelSize = 4 * sizeof(GLfloat);
558    }
559
560    /* Allocate the src/dst row buffers.
561     * Keep two adjacent src rows around for bilinear sampling.
562     */
563    srcBuffer0 = malloc(pixelSize * srcWidth);
564    srcBuffer1 = malloc(pixelSize * srcWidth);
565    dstBuffer = malloc(pixelSize * dstWidth);
566    if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
567       goto fail_no_memory;
568    }
569
570    for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
571       GLint idx = drawFb->_ColorDrawBufferIndexes[i];
572       struct gl_renderbuffer_attachment *drawAtt;
573       struct gl_renderbuffer *drawRb;
574       gl_format drawFormat;
575
576       if (idx == -1)
577          continue;
578
579       drawAtt = &drawFb->Attachment[idx];
580       drawRb = drawAtt->Renderbuffer;
581       if (!drawRb)
582          continue;
583
584       drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
585
586       /*
587        * Map src / dst renderbuffers
588        */
589       if ((readRb == drawRb) ||
590           (readAtt->Texture && drawAtt->Texture &&
591            (readAtt->Texture == drawAtt->Texture))) {
592          /* map whole buffer for read/write */
593          ctx->Driver.MapRenderbuffer(ctx, readRb,
594                                      0, 0, readRb->Width, readRb->Height,
595                                      GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
596                                      &srcMap, &srcRowStride);
597          if (!srcMap) {
598             goto fail_no_memory;
599          }
600
601          dstMap = srcMap;
602          dstRowStride = srcRowStride;
603       }
604       else {
605          /* different src/dst buffers */
606          /* XXX with a bit of work we could just map the regions to be
607           * read/written instead of the whole buffers.
608           */
609          ctx->Driver.MapRenderbuffer(ctx, readRb,
610                                      0, 0, readRb->Width, readRb->Height,
611                                      GL_MAP_READ_BIT, &srcMap, &srcRowStride);
612          if (!srcMap) {
613             goto fail_no_memory;
614          }
615          ctx->Driver.MapRenderbuffer(ctx, drawRb,
616                                      0, 0, drawRb->Width, drawRb->Height,
617                                      GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
618          if (!dstMap) {
619             ctx->Driver.UnmapRenderbuffer(ctx, readRb);
620             goto fail_no_memory;
621          }
622       }
623
624       for (dstRow = 0; dstRow < dstHeight; dstRow++) {
625          const GLint dstY = dstYpos + dstRow;
626          GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
627          GLint srcRow0 = MAX2(0, IFLOOR(srcRow));
628          GLint srcRow1 = srcRow0 + 1;
629          GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
630
631          if (srcRow1 == srcHeight) {
632             /* last row fudge */
633             srcRow1 = srcRow0;
634             rowWeight = 0.0;
635          }
636
637          if (invertY) {
638             srcRow0 = srcHeight - 1 - srcRow0;
639             srcRow1 = srcHeight - 1 - srcRow1;
640          }
641
642          srcY0 = srcYpos + srcRow0;
643          srcY1 = srcYpos + srcRow1;
644
645          /* get the two source rows */
646          if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
647             /* use same source row buffers again */
648          }
649          else if (srcY0 == srcBufferY1) {
650             /* move buffer1 into buffer0 by swapping pointers */
651             GLvoid *tmp = srcBuffer0;
652             srcBuffer0 = srcBuffer1;
653             srcBuffer1 = tmp;
654             /* get y1 row */
655             {
656                GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
657                if (pixelType == GL_UNSIGNED_BYTE) {
658                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
659                                               src, srcBuffer1);
660                }
661                else {
662                   _mesa_unpack_rgba_row(readFormat, srcWidth,
663                                         src, srcBuffer1);
664                }
665             }
666             srcBufferY0 = srcY0;
667             srcBufferY1 = srcY1;
668          }
669          else {
670             /* get both new rows */
671             {
672                GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
673                GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
674                if (pixelType == GL_UNSIGNED_BYTE) {
675                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
676                                               src0, srcBuffer0);
677                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
678                                               src1, srcBuffer1);
679                }
680                else {
681                   _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
682                   _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
683                }
684             }
685             srcBufferY0 = srcY0;
686             srcBufferY1 = srcY1;
687          }
688
689          if (pixelType == GL_UNSIGNED_BYTE) {
690             resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
691                                    dstBuffer, invertX, rowWeight);
692          }
693          else {
694             resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
695                                       dstBuffer, invertX, rowWeight);
696          }
697
698          /* store pixel row in destination */
699          {
700             GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
701             if (pixelType == GL_UNSIGNED_BYTE) {
702                _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
703             }
704             else {
705                _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
706             }
707          }
708       }
709
710       ctx->Driver.UnmapRenderbuffer(ctx, readRb);
711       if (drawRb != readRb) {
712          ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
713       }
714    }
715
716    free(srcBuffer0);
717    free(srcBuffer1);
718    free(dstBuffer);
719    return;
720
721 fail_no_memory:
722    free(srcBuffer0);
723    free(srcBuffer1);
724    free(dstBuffer);
725    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
726 }
727
728
729
730 /**
731  * Software fallback for glBlitFramebufferEXT().
732  */
733 void
734 _swrast_BlitFramebuffer(struct gl_context *ctx,
735                         GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
736                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
737                         GLbitfield mask, GLenum filter)
738 {
739    static const GLbitfield buffers[3] = {
740       GL_COLOR_BUFFER_BIT,
741       GL_DEPTH_BUFFER_BIT,
742       GL_STENCIL_BUFFER_BIT
743    };
744    static const GLenum buffer_enums[3] = {
745       GL_COLOR,
746       GL_DEPTH,
747       GL_STENCIL,
748    };
749    GLint i;
750
751    if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
752                         &dstX0, &dstY0, &dstX1, &dstY1)) {
753       return;
754    }
755
756    if (SWRAST_CONTEXT(ctx)->NewState)
757       _swrast_validate_derived(ctx);
758
759    /* First, try covering whatever buffers possible using the fast 1:1 copy
760     * path.
761     */
762    if (srcX1 - srcX0 == dstX1 - dstX0 &&
763        srcY1 - srcY0 == dstY1 - dstY0 &&
764        srcX0 < srcX1 &&
765        srcY0 < srcY1 &&
766        dstX0 < dstX1 &&
767        dstY0 < dstY1) {
768       for (i = 0; i < 3; i++) {
769          if (mask & buffers[i]) {
770             if (swrast_fast_copy_pixels(ctx,
771                                         srcX0, srcY0,
772                                         srcX1 - srcX0, srcY1 - srcY0,
773                                         dstX0, dstY0,
774                                         buffer_enums[i])) {
775                mask &= ~buffers[i];
776             }
777          }
778       }
779
780       if (!mask)
781          return;
782    }
783
784    if (filter == GL_NEAREST) {
785       for (i = 0; i < 3; i++) {
786          if (mask & buffers[i]) {
787             blit_nearest(ctx,  srcX0, srcY0, srcX1, srcY1,
788                          dstX0, dstY0, dstX1, dstY1, buffers[i]);
789          }
790       }
791    }
792    else {
793       ASSERT(filter == GL_LINEAR);
794       if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
795          blit_linear(ctx,  srcX0, srcY0, srcX1, srcY1,
796                      dstX0, dstY0, dstX1, dstY1);
797       }
798    }
799
800 }