2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
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"
35 #define ABS(X) ((X) < 0 ? -(X) : (X))
39 * Generate a row resampler function for GL_NEAREST mode.
41 #define RESAMPLE(NAME, PIXELTYPE, SIZE) \
43 NAME(GLint srcWidth, GLint dstWidth, \
44 const GLvoid *srcBuffer, GLvoid *dstBuffer, \
47 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
48 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \
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 */ \
58 dst[dstCol] = src[srcCol]; \
60 else if (SIZE == 2) { \
61 dst[dstCol*2+0] = src[srcCol*2+0]; \
62 dst[dstCol*2+1] = src[srcCol*2+1]; \
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]; \
73 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
74 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
75 ASSERT(srcCol >= 0); \
76 ASSERT(srcCol < srcWidth); \
78 dst[dstCol] = src[srcCol]; \
80 else if (SIZE == 2) { \
81 dst[dstCol*2+0] = src[srcCol*2+0]; \
82 dst[dstCol*2+1] = src[srcCol*2+1]; \
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]; \
95 * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
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)
105 * Blit color, depth or stencil with GL_NEAREST filtering.
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
,
113 struct gl_renderbuffer
*readRb
, *drawRb
;
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
);
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
);
125 const GLboolean invertX
= (srcX1
< srcX0
) ^ (dstX1
< dstX0
);
126 const GLboolean invertY
= (srcY1
< srcY0
) ^ (dstY1
< dstY0
);
134 GLubyte
*srcMap
, *dstMap
;
135 GLint srcRowStride
, dstRowStride
;
139 GLvoid
*srcBuffer
, *dstBuffer
;
142 typedef void (*resample_func
)(GLint srcWidth
, GLint dstWidth
,
143 const GLvoid
*srcBuffer
, GLvoid
*dstBuffer
,
145 resample_func resampleRow
;
148 case GL_COLOR_BUFFER_BIT
:
149 readRb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
150 drawRb
= ctx
->DrawBuffer
->_ColorDrawBuffers
[0];
152 if (readRb
->Format
== drawRb
->Format
) {
154 pixelSize
= _mesa_get_format_bytes(readRb
->Format
);
156 mode
= UNPACK_RGBA_FLOAT
;
161 case GL_DEPTH_BUFFER_BIT
:
162 readRb
= ctx
->ReadBuffer
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
163 drawRb
= ctx
->DrawBuffer
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
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.
169 if (readRb
->Format
== MESA_FORMAT_Z32_FLOAT
||
170 readRb
->Format
== MESA_FORMAT_Z32_FLOAT_X24S8
) {
171 mode
= UNPACK_Z_FLOAT
;
177 case GL_STENCIL_BUFFER_BIT
:
178 readRb
= ctx
->ReadBuffer
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
179 drawRb
= ctx
->DrawBuffer
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
184 _mesa_problem(ctx
, "unexpected buffer in blit_nearest()");
188 /* choose row resampler */
191 resampleRow
= resample_row_1
;
194 resampleRow
= resample_row_2
;
197 resampleRow
= resample_row_4
;
200 resampleRow
= resample_row_8
;
203 resampleRow
= resample_row_16
;
206 _mesa_problem(ctx
, "unexpected pixel size (%d) in blit_nearest",
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.
218 GLint formatSize
= _mesa_get_format_bytes(readRb
->Format
);
220 ctx
->Driver
.MapRenderbuffer(ctx
, readRb
, 0, 0,
221 readRb
->Width
, readRb
->Height
,
222 GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
,
225 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
229 srcMap
= map
+ srcYpos
* rowStride
+ srcXpos
* formatSize
;
230 dstMap
= map
+ dstYpos
* rowStride
+ dstXpos
* formatSize
;
232 /* this handles overlapping copies */
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
;
241 /* copy in normal (bottom->up) order */
242 srcRowStride
= rowStride
;
243 dstRowStride
= rowStride
;
247 /* different src/dst buffers */
248 ctx
->Driver
.MapRenderbuffer(ctx
, readRb
,
251 GL_MAP_READ_BIT
, &srcMap
, &srcRowStride
);
253 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
256 ctx
->Driver
.MapRenderbuffer(ctx
, drawRb
,
259 GL_MAP_WRITE_BIT
, &dstMap
, &dstRowStride
);
261 ctx
->Driver
.UnmapRenderbuffer(ctx
, readRb
);
262 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
267 /* allocate the src/dst row buffers */
268 srcBuffer
= malloc(pixelSize
* srcWidth
);
270 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
273 dstBuffer
= malloc(pixelSize
* dstWidth
);
276 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
280 for (dstRow
= 0; dstRow
< dstHeight
; dstRow
++) {
281 GLint srcRow
= (dstRow
* srcHeight
) / dstHeight
;
282 GLubyte
*dstRowStart
= dstMap
+ dstRowStride
* dstRow
;
285 ASSERT(srcRow
< srcHeight
);
288 srcRow
= srcHeight
- 1 - srcRow
;
291 /* get pixel row from source and resample to match dest width */
292 if (prevY
!= srcRow
) {
293 GLubyte
*srcRowStart
= srcMap
+ srcRowStride
* srcRow
;
297 memcpy(srcBuffer
, srcRowStart
, pixelSize
* srcWidth
);
299 case UNPACK_RGBA_FLOAT
:
300 _mesa_unpack_rgba_row(readRb
->Format
, srcWidth
, srcRowStart
,
304 _mesa_unpack_float_z_row(readRb
->Format
, srcWidth
, srcRowStart
,
308 _mesa_unpack_uint_z_row(readRb
->Format
, srcWidth
, srcRowStart
,
312 _mesa_unpack_ubyte_stencil_row(readRb
->Format
, srcWidth
,
313 srcRowStart
, srcBuffer
);
317 (*resampleRow
)(srcWidth
, dstWidth
, srcBuffer
, dstBuffer
, invertX
);
321 /* store pixel row in destination */
324 memcpy(dstRowStart
, dstBuffer
, pixelSize
* srcWidth
);
326 case UNPACK_RGBA_FLOAT
:
327 _mesa_pack_float_rgba_row(drawRb
->Format
, dstWidth
, dstBuffer
,
331 _mesa_pack_float_z_row(drawRb
->Format
, dstWidth
, dstBuffer
,
335 _mesa_pack_uint_z_row(drawRb
->Format
, dstWidth
, dstBuffer
,
339 _mesa_pack_ubyte_stencil_row(drawRb
->Format
, dstWidth
, dstBuffer
,
348 ctx
->Driver
.UnmapRenderbuffer(ctx
, readRb
);
349 if (drawRb
!= readRb
) {
350 ctx
->Driver
.UnmapRenderbuffer(ctx
, drawRb
);
356 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
358 static inline GLfloat
359 lerp_2d(GLfloat a
, GLfloat b
,
360 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
362 const GLfloat temp0
= LERP(a
, v00
, v10
);
363 const GLfloat temp1
= LERP(a
, v01
, v11
);
364 return LERP(b
, temp0
, temp1
);
369 * Bilinear interpolation of two source rows.
373 resample_linear_row_ub(GLint srcWidth
, GLint dstWidth
,
374 const GLvoid
*srcBuffer0
, const GLvoid
*srcBuffer1
,
375 GLvoid
*dstBuffer
, GLboolean flip
, GLfloat rowWeight
)
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
;
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
;
390 ASSERT(srcCol0
>= 0);
391 ASSERT(srcCol0
< srcWidth
);
392 ASSERT(srcCol1
<= srcWidth
);
394 if (srcCol1
== srcWidth
) {
395 /* last column fudge */
401 srcCol0
= srcWidth
- 1 - srcCol0
;
402 srcCol1
= srcWidth
- 1 - srcCol1
;
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
]);
418 dstColor
[dstCol
][RCOMP
] = IFLOOR(red
);
419 dstColor
[dstCol
][GCOMP
] = IFLOOR(green
);
420 dstColor
[dstCol
][BCOMP
] = IFLOOR(blue
);
421 dstColor
[dstCol
][ACOMP
] = IFLOOR(alpha
);
427 * Bilinear interpolation of two source rows. floating point pixels.
430 resample_linear_row_float(GLint srcWidth
, GLint dstWidth
,
431 const GLvoid
*srcBuffer0
, const GLvoid
*srcBuffer1
,
432 GLvoid
*dstBuffer
, GLboolean flip
, GLfloat rowWeight
)
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
;
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
;
447 ASSERT(srcCol0
>= 0);
448 ASSERT(srcCol0
< srcWidth
);
449 ASSERT(srcCol1
<= srcWidth
);
451 if (srcCol1
== srcWidth
) {
452 /* last column fudge */
458 srcCol0
= srcWidth
- 1 - srcCol0
;
459 srcCol1
= srcWidth
- 1 - srcCol1
;
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
]);
475 dstColor
[dstCol
][RCOMP
] = red
;
476 dstColor
[dstCol
][GCOMP
] = green
;
477 dstColor
[dstCol
][BCOMP
] = blue
;
478 dstColor
[dstCol
][ACOMP
] = alpha
;
485 * Bilinear filtered blit (color only, non-integer values).
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
)
492 struct gl_renderbuffer
*readRb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
493 struct gl_renderbuffer
*drawRb
= ctx
->DrawBuffer
->_ColorDrawBuffers
[0];
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
;
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
);
506 const GLboolean invertX
= (srcX1
< srcX0
) ^ (dstX1
< dstX0
);
507 const GLboolean invertY
= (srcY1
< srcY0
) ^ (dstY1
< dstY0
);
512 GLvoid
*srcBuffer0
, *srcBuffer1
;
513 GLint srcBufferY0
= -1, srcBufferY1
= -1;
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
);
522 GLubyte
*srcMap
, *dstMap
;
523 GLint srcRowStride
, dstRowStride
;
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
);
533 pixelType
= GL_FLOAT
;
534 pixelSize
= 4 * sizeof(GLfloat
);
537 /* Allocate the src/dst row buffers.
538 * Keep two adjacent src rows around for bilinear sampling.
540 srcBuffer0
= malloc(pixelSize
* srcWidth
);
542 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
545 srcBuffer1
= malloc(pixelSize
* srcWidth
);
548 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
551 dstBuffer
= malloc(pixelSize
* dstWidth
);
555 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
560 * Map src / dst renderbuffers
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
);
572 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
577 dstRowStride
= srcRowStride
;
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.
584 ctx
->Driver
.MapRenderbuffer(ctx
, readRb
,
585 0, 0, readRb
->Width
, readRb
->Height
,
586 GL_MAP_READ_BIT
, &srcMap
, &srcRowStride
);
591 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
594 ctx
->Driver
.MapRenderbuffer(ctx
, drawRb
,
595 0, 0, drawRb
->Width
, drawRb
->Height
,
596 GL_MAP_WRITE_BIT
, &dstMap
, &dstRowStride
);
598 ctx
->Driver
.UnmapRenderbuffer(ctx
, readRb
);
602 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFramebuffer");
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 */
615 ASSERT(srcRow
< srcHeight
);
617 if (srcRow1
== srcHeight
) {
624 srcRow0
= srcHeight
- 1 - srcRow0
;
625 srcRow1
= srcHeight
- 1 - srcRow1
;
628 srcY0
= srcYpos
+ srcRow0
;
629 srcY1
= srcYpos
+ srcRow1
;
631 /* get the two source rows */
632 if (srcY0
== srcBufferY0
&& srcY1
== srcBufferY1
) {
633 /* use same source row buffers again */
635 else if (srcY0
== srcBufferY1
) {
636 /* move buffer1 into buffer0 by swapping pointers */
637 GLvoid
*tmp
= srcBuffer0
;
638 srcBuffer0
= srcBuffer1
;
642 GLubyte
*src
= srcMap
+ srcY1
* srcRowStride
+ srcXpos
* bpp
;
643 if (pixelType
== GL_UNSIGNED_BYTE
) {
644 _mesa_unpack_ubyte_rgba_row(readFormat
, srcWidth
,
648 _mesa_unpack_rgba_row(readFormat
, srcWidth
,
656 /* get both new rows */
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
,
663 _mesa_unpack_ubyte_rgba_row(readFormat
, srcWidth
,
667 _mesa_unpack_rgba_row(readFormat
, srcWidth
, src0
, srcBuffer0
);
668 _mesa_unpack_rgba_row(readFormat
, srcWidth
, src1
, srcBuffer1
);
675 if (pixelType
== GL_UNSIGNED_BYTE
) {
676 resample_linear_row_ub(srcWidth
, dstWidth
, srcBuffer0
, srcBuffer1
,
677 dstBuffer
, invertX
, rowWeight
);
680 resample_linear_row_float(srcWidth
, dstWidth
, srcBuffer0
, srcBuffer1
,
681 dstBuffer
, invertX
, rowWeight
);
684 /* store pixel row in destination */
686 GLubyte
*dst
= dstMap
+ dstY
* dstRowStride
+ dstXpos
* bpp
;
687 if (pixelType
== GL_UNSIGNED_BYTE
) {
688 _mesa_pack_ubyte_rgba_row(drawFormat
, dstWidth
, dstBuffer
, dst
);
691 _mesa_pack_float_rgba_row(drawFormat
, dstWidth
, dstBuffer
, dst
);
700 ctx
->Driver
.UnmapRenderbuffer(ctx
, readRb
);
701 if (drawRb
!= readRb
) {
702 ctx
->Driver
.UnmapRenderbuffer(ctx
, drawRb
);
709 * Software fallback for glBlitFramebufferEXT().
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
)
717 static const GLbitfield buffers
[3] = {
720 GL_STENCIL_BUFFER_BIT
722 static const GLenum buffer_enums
[3] = {
729 if (!_mesa_clip_blit(ctx
, &srcX0
, &srcY0
, &srcX1
, &srcY1
,
730 &dstX0
, &dstY0
, &dstX1
, &dstY1
)) {
734 if (SWRAST_CONTEXT(ctx
)->NewState
)
735 _swrast_validate_derived(ctx
);
737 /* First, try covering whatever buffers possible using the fast 1:1 copy
740 if (srcX1
- srcX0
== dstX1
- dstX0
&&
741 srcY1
- srcY0
== dstY1
- dstY0
&&
746 for (i
= 0; i
< 3; i
++) {
747 if (mask
& buffers
[i
]) {
748 if (swrast_fast_copy_pixels(ctx
,
750 srcX1
- srcX0
, srcY1
- srcY0
,
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
]);
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
);