• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          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 
369 fail:
370    free(srcBuffer);
371    free(dstBuffer);
372    return;
373 
374 fail_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 
384 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)385 lerp_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  */
398 static void
resample_linear_row_ub(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)399 resample_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  */
453 static void
resample_linear_row_float(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)454 resample_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  */
509 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)510 blit_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 
722 fail_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  */
734 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)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