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