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)			\
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
blit_nearest(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield buffer)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;
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 
358 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)359 lerp_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  */
372 static void
resample_linear_row_ub(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)373 resample_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  */
429 static void
resample_linear_row_float(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)430 resample_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  */
487 static void
blit_linear(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1)488 blit_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  */
711 void
_swrast_BlitFramebuffer(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)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