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