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)			\
43 static void						\
44 NAME(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  */
98 RESAMPLE(resample_row_1, GLubyte, 1)
99 RESAMPLE(resample_row_2, GLushort, 1)
100 RESAMPLE(resample_row_4, GLuint, 1)
101 RESAMPLE(resample_row_8, GLuint, 2)
102 RESAMPLE(resample_row_16, GLuint, 4)
103 
104 
105 /**
106  * Blit color, depth or stencil with GL_NEAREST filtering.
107  */
108 static void
blit_nearest(struct gl_context * ctx,struct gl_framebuffer * readFb,struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield buffer)109 blit_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          gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
202          if (idx == BUFFER_NONE)
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, readFb->FlipY);
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                                      readFb->FlipY);
285          if (!srcMap) {
286             goto fail_no_memory;
287          }
288          ctx->Driver.MapRenderbuffer(ctx, drawRb,
289                                      dstXpos, dstYpos,
290                                      dstWidth, dstHeight,
291                                      GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
292                                      drawFb->FlipY);
293          if (!dstMap) {
294             ctx->Driver.UnmapRenderbuffer(ctx, readRb);
295             goto fail_no_memory;
296          }
297       }
298 
299       for (dstRow = 0; dstRow < dstHeight; dstRow++) {
300          GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
301          GLint srcRow = lroundf(srcRowF);
302          GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
303 
304          assert(srcRow >= 0);
305          assert(srcRow < srcHeight);
306 
307          if (invertY) {
308             srcRow = srcHeight - 1 - srcRow;
309          }
310 
311          /* get pixel row from source and resample to match dest width */
312          if (prevY != srcRow) {
313             GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
314 
315             switch (mode) {
316             case DIRECT:
317                memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
318                break;
319             case UNPACK_RGBA_FLOAT:
320                _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
321                                      srcBuffer);
322                break;
323             case UNPACK_Z_FLOAT:
324                _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
325                                         srcBuffer);
326                break;
327             case UNPACK_Z_INT:
328                _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
329                                        srcBuffer);
330                break;
331             case UNPACK_S:
332                _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
333                                               srcRowStart, srcBuffer);
334                break;
335             }
336 
337             resampleRow(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
338             prevY = srcRow;
339          }
340 
341          /* store pixel row in destination */
342          switch (mode) {
343          case DIRECT:
344             memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
345             break;
346          case UNPACK_RGBA_FLOAT:
347             _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
348                                       dstRowStart);
349             break;
350          case UNPACK_Z_FLOAT:
351             _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
352                                    dstRowStart);
353             break;
354          case UNPACK_Z_INT:
355             _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
356                                   dstRowStart);
357             break;
358          case UNPACK_S:
359             _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
360                                          dstRowStart);
361             break;
362          }
363       }
364 
365       ctx->Driver.UnmapRenderbuffer(ctx, readRb);
366       if (drawRb != readRb) {
367          ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
368       }
369    }
370 
371 fail:
372    free(srcBuffer);
373    free(dstBuffer);
374    return;
375 
376 fail_no_memory:
377    free(srcBuffer);
378    free(dstBuffer);
379    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
380 }
381 
382 
383 
384 #define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
385 
386 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)387 lerp_2d(GLfloat a, GLfloat b,
388         GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
389 {
390    const GLfloat temp0 = LERP(a, v00, v10);
391    const GLfloat temp1 = LERP(a, v01, v11);
392    return LERP(b, temp0, temp1);
393 }
394 
395 
396 /**
397  * Bilinear interpolation of two source rows.
398  * GLubyte pixels.
399  */
400 static void
resample_linear_row_ub(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)401 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
402                        const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
403                        GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
404 {
405    const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
406    const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
407    GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
408    GLint dstCol;
409 
410    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
411       const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
412       GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
413       GLint srcCol1 = srcCol0 + 1;
414       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
415       GLfloat red, green, blue, alpha;
416 
417       assert(srcCol0 < srcWidth);
418       assert(srcCol1 <= srcWidth);
419 
420       if (srcCol1 == srcWidth) {
421          /* last column fudge */
422          srcCol1--;
423          colWeight = 0.0;
424       }
425 
426       if (flip) {
427          srcCol0 = srcWidth - 1 - srcCol0;
428          srcCol1 = srcWidth - 1 - srcCol1;
429       }
430 
431       red = lerp_2d(colWeight, rowWeight,
432                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
433                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
434       green = lerp_2d(colWeight, rowWeight,
435                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
436                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
437       blue = lerp_2d(colWeight, rowWeight,
438                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
439                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
440       alpha = lerp_2d(colWeight, rowWeight,
441                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
442                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
443 
444       dstColor[dstCol][RCOMP] = util_ifloor(red);
445       dstColor[dstCol][GCOMP] = util_ifloor(green);
446       dstColor[dstCol][BCOMP] = util_ifloor(blue);
447       dstColor[dstCol][ACOMP] = util_ifloor(alpha);
448    }
449 }
450 
451 
452 /**
453  * Bilinear interpolation of two source rows.  floating point pixels.
454  */
455 static void
resample_linear_row_float(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)456 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
457                           const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
458                           GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
459 {
460    const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
461    const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
462    GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
463    GLint dstCol;
464 
465    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
466       const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
467       GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
468       GLint srcCol1 = srcCol0 + 1;
469       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
470       GLfloat red, green, blue, alpha;
471 
472       assert(srcCol0 < srcWidth);
473       assert(srcCol1 <= srcWidth);
474 
475       if (srcCol1 == srcWidth) {
476          /* last column fudge */
477          srcCol1--;
478          colWeight = 0.0;
479       }
480 
481       if (flip) {
482          srcCol0 = srcWidth - 1 - srcCol0;
483          srcCol1 = srcWidth - 1 - srcCol1;
484       }
485 
486       red = lerp_2d(colWeight, rowWeight,
487                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
488                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
489       green = lerp_2d(colWeight, rowWeight,
490                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
491                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
492       blue = lerp_2d(colWeight, rowWeight,
493                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
494                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
495       alpha = lerp_2d(colWeight, rowWeight,
496                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
497                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
498 
499       dstColor[dstCol][RCOMP] = red;
500       dstColor[dstCol][GCOMP] = green;
501       dstColor[dstCol][BCOMP] = blue;
502       dstColor[dstCol][ACOMP] = alpha;
503    }
504 }
505 
506 
507 
508 /**
509  * Bilinear filtered blit (color only, non-integer values).
510  */
511 static void
blit_linear(struct gl_context * ctx,struct gl_framebuffer * readFb,struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1)512 blit_linear(struct gl_context *ctx,
513             struct gl_framebuffer *readFb,
514             struct gl_framebuffer *drawFb,
515             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
516             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
517 {
518    struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
519    struct gl_renderbuffer_attachment *readAtt =
520       &readFb->Attachment[readFb->_ColorReadBufferIndex];
521 
522    const GLint srcWidth = ABS(srcX1 - srcX0);
523    const GLint dstWidth = ABS(dstX1 - dstX0);
524    const GLint srcHeight = ABS(srcY1 - srcY0);
525    const GLint dstHeight = ABS(dstY1 - dstY0);
526 
527    const GLint srcXpos = MIN2(srcX0, srcX1);
528    const GLint srcYpos = MIN2(srcY0, srcY1);
529    const GLint dstXpos = MIN2(dstX0, dstX1);
530    const GLint dstYpos = MIN2(dstY0, dstY1);
531 
532    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
533    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
534 
535    GLint dstRow;
536 
537    GLint pixelSize;
538    GLvoid *srcBuffer0, *srcBuffer1;
539    GLint srcBufferY0 = -1, srcBufferY1 = -1;
540    GLvoid *dstBuffer;
541 
542    mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
543    GLuint bpp = _mesa_get_format_bytes(readFormat);
544 
545    GLenum pixelType;
546 
547    GLubyte *srcMap, *dstMap;
548    GLint srcRowStride, dstRowStride;
549    GLuint i;
550 
551 
552    /* Determine datatype for resampling */
553    if (_mesa_get_format_max_bits(readFormat) == 8 &&
554        _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
555       pixelType = GL_UNSIGNED_BYTE;
556       pixelSize = 4 * sizeof(GLubyte);
557    }
558    else {
559       pixelType = GL_FLOAT;
560       pixelSize = 4 * sizeof(GLfloat);
561    }
562 
563    /* Allocate the src/dst row buffers.
564     * Keep two adjacent src rows around for bilinear sampling.
565     */
566    srcBuffer0 = malloc(pixelSize * srcWidth);
567    srcBuffer1 = malloc(pixelSize * srcWidth);
568    dstBuffer = malloc(pixelSize * dstWidth);
569    if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
570       goto fail_no_memory;
571    }
572 
573    for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
574       gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
575       struct gl_renderbuffer_attachment *drawAtt;
576       struct gl_renderbuffer *drawRb;
577       mesa_format drawFormat;
578 
579       if (idx == BUFFER_NONE)
580          continue;
581 
582       drawAtt = &drawFb->Attachment[idx];
583       drawRb = drawAtt->Renderbuffer;
584       if (!drawRb)
585          continue;
586 
587       drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
588 
589       /*
590        * Map src / dst renderbuffers
591        */
592       if ((readRb == drawRb) ||
593           (readAtt->Texture && drawAtt->Texture &&
594            (readAtt->Texture == drawAtt->Texture))) {
595          /* map whole buffer for read/write */
596          ctx->Driver.MapRenderbuffer(ctx, readRb,
597                                      0, 0, readRb->Width, readRb->Height,
598                                      GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
599                                      &srcMap, &srcRowStride,
600                                      readFb->FlipY);
601          if (!srcMap) {
602             goto fail_no_memory;
603          }
604 
605          dstMap = srcMap;
606          dstRowStride = srcRowStride;
607       }
608       else {
609          /* different src/dst buffers */
610          /* XXX with a bit of work we could just map the regions to be
611           * read/written instead of the whole buffers.
612           */
613          ctx->Driver.MapRenderbuffer(ctx, readRb,
614                                      0, 0, readRb->Width, readRb->Height,
615                                      GL_MAP_READ_BIT, &srcMap, &srcRowStride,
616                                      readFb->FlipY);
617          if (!srcMap) {
618             goto fail_no_memory;
619          }
620          ctx->Driver.MapRenderbuffer(ctx, drawRb,
621                                      0, 0, drawRb->Width, drawRb->Height,
622                                      GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
623                                      drawFb->FlipY);
624          if (!dstMap) {
625             ctx->Driver.UnmapRenderbuffer(ctx, readRb);
626             goto fail_no_memory;
627          }
628       }
629 
630       for (dstRow = 0; dstRow < dstHeight; dstRow++) {
631          const GLint dstY = dstYpos + dstRow;
632          GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
633          GLint srcRow0 = MAX2(0, util_ifloor(srcRow));
634          GLint srcRow1 = srcRow0 + 1;
635          GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
636 
637          if (srcRow1 == srcHeight) {
638             /* last row fudge */
639             srcRow1 = srcRow0;
640             rowWeight = 0.0;
641          }
642 
643          if (invertY) {
644             srcRow0 = srcHeight - 1 - srcRow0;
645             srcRow1 = srcHeight - 1 - srcRow1;
646          }
647 
648          srcY0 = srcYpos + srcRow0;
649          srcY1 = srcYpos + srcRow1;
650 
651          /* get the two source rows */
652          if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
653             /* use same source row buffers again */
654          }
655          else if (srcY0 == srcBufferY1) {
656             /* move buffer1 into buffer0 by swapping pointers */
657             GLvoid *tmp = srcBuffer0;
658             srcBuffer0 = srcBuffer1;
659             srcBuffer1 = tmp;
660             /* get y1 row */
661             {
662                GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
663                if (pixelType == GL_UNSIGNED_BYTE) {
664                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
665                                               src, srcBuffer1);
666                }
667                else {
668                   _mesa_unpack_rgba_row(readFormat, srcWidth,
669                                         src, srcBuffer1);
670                }
671             }
672             srcBufferY0 = srcY0;
673             srcBufferY1 = srcY1;
674          }
675          else {
676             /* get both new rows */
677             {
678                GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
679                GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
680                if (pixelType == GL_UNSIGNED_BYTE) {
681                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
682                                               src0, srcBuffer0);
683                   _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
684                                               src1, srcBuffer1);
685                }
686                else {
687                   _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
688                   _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
689                }
690             }
691             srcBufferY0 = srcY0;
692             srcBufferY1 = srcY1;
693          }
694 
695          if (pixelType == GL_UNSIGNED_BYTE) {
696             resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
697                                    dstBuffer, invertX, rowWeight);
698          }
699          else {
700             resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
701                                       dstBuffer, invertX, rowWeight);
702          }
703 
704          /* store pixel row in destination */
705          {
706             GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
707             if (pixelType == GL_UNSIGNED_BYTE) {
708                _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
709             }
710             else {
711                _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
712             }
713          }
714       }
715 
716       ctx->Driver.UnmapRenderbuffer(ctx, readRb);
717       if (drawRb != readRb) {
718          ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
719       }
720    }
721 
722    free(srcBuffer0);
723    free(srcBuffer1);
724    free(dstBuffer);
725    return;
726 
727 fail_no_memory:
728    free(srcBuffer0);
729    free(srcBuffer1);
730    free(dstBuffer);
731    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
732 }
733 
734 
735 
736 /**
737  * Software fallback for glBlitFramebufferEXT().
738  */
739 void
_swrast_BlitFramebuffer(struct gl_context * ctx,struct gl_framebuffer * readFb,struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)740 _swrast_BlitFramebuffer(struct gl_context *ctx,
741                         struct gl_framebuffer *readFb,
742                         struct gl_framebuffer *drawFb,
743                         GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
744                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
745                         GLbitfield mask, GLenum filter)
746 {
747    static const GLbitfield buffers[3] = {
748       GL_COLOR_BUFFER_BIT,
749       GL_DEPTH_BUFFER_BIT,
750       GL_STENCIL_BUFFER_BIT
751    };
752    static const GLenum buffer_enums[3] = {
753       GL_COLOR,
754       GL_DEPTH,
755       GL_STENCIL,
756    };
757    GLint i;
758 
759    /* Page 679 of OpenGL 4.4 spec says:
760     *    "Added BlitFramebuffer to commands affected by conditional rendering in
761     *     section 10.10 (Bug 9562)."
762     */
763    if (!_mesa_check_conditional_render(ctx))
764       return; /* Do not blit */
765 
766    if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1,
767                         &dstX0, &dstY0, &dstX1, &dstY1)) {
768       return;
769    }
770 
771    if (SWRAST_CONTEXT(ctx)->NewState)
772       _swrast_validate_derived(ctx);
773 
774    /* First, try covering whatever buffers possible using the fast 1:1 copy
775     * path.
776     */
777    if (srcX1 - srcX0 == dstX1 - dstX0 &&
778        srcY1 - srcY0 == dstY1 - dstY0 &&
779        srcX0 < srcX1 &&
780        srcY0 < srcY1 &&
781        dstX0 < dstX1 &&
782        dstY0 < dstY1) {
783       for (i = 0; i < 3; i++) {
784          if (mask & buffers[i]) {
785             if (swrast_fast_copy_pixels(ctx,
786                                         readFb, drawFb,
787                                         srcX0, srcY0,
788                                         srcX1 - srcX0, srcY1 - srcY0,
789                                         dstX0, dstY0,
790                                         buffer_enums[i])) {
791                mask &= ~buffers[i];
792             }
793          }
794       }
795 
796       if (!mask)
797          return;
798    }
799 
800    if (filter == GL_NEAREST) {
801       for (i = 0; i < 3; i++) {
802           if (mask & buffers[i]) {
803              blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
804                           dstX0, dstY0, dstX1, dstY1, buffers[i]);
805           }
806       }
807    }
808    else {
809       assert(filter == GL_LINEAR);
810       if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
811          blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
812                      dstX0, dstY0, dstX1, dstY1);
813       }
814    }
815 
816 }
817