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/image.h"
28 #include "main/macros.h"
29 #include "s_context.h"
32 #define ABS(X) ((X) < 0 ? -(X) : (X))
36 * Generate a row resampler function for GL_NEAREST mode.
38 #define RESAMPLE(NAME, PIXELTYPE, SIZE) \
40 NAME(GLint srcWidth, GLint dstWidth, \
41 const GLvoid *srcBuffer, GLvoid *dstBuffer, \
44 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
45 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \
49 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
50 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
51 ASSERT(srcCol >= 0); \
52 ASSERT(srcCol < srcWidth); \
53 srcCol = srcWidth - 1 - srcCol; /* flip */ \
55 dst[dstCol] = src[srcCol]; \
57 else if (SIZE == 2) { \
58 dst[dstCol*2+0] = src[srcCol*2+0]; \
59 dst[dstCol*2+1] = src[srcCol*2+1]; \
61 else if (SIZE == 4) { \
62 dst[dstCol*4+0] = src[srcCol*4+0]; \
63 dst[dstCol*4+1] = src[srcCol*4+1]; \
64 dst[dstCol*4+2] = src[srcCol*4+2]; \
65 dst[dstCol*4+3] = src[srcCol*4+3]; \
70 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
71 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
72 ASSERT(srcCol >= 0); \
73 ASSERT(srcCol < srcWidth); \
75 dst[dstCol] = src[srcCol]; \
77 else if (SIZE == 2) { \
78 dst[dstCol*2+0] = src[srcCol*2+0]; \
79 dst[dstCol*2+1] = src[srcCol*2+1]; \
81 else if (SIZE == 4) { \
82 dst[dstCol*4+0] = src[srcCol*4+0]; \
83 dst[dstCol*4+1] = src[srcCol*4+1]; \
84 dst[dstCol*4+2] = src[srcCol*4+2]; \
85 dst[dstCol*4+3] = src[srcCol*4+3]; \
92 * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
94 RESAMPLE(resample_row_1
, GLubyte
, 1)
95 RESAMPLE(resample_row_2
, GLushort
, 1)
96 RESAMPLE(resample_row_4
, GLuint
, 1)
97 RESAMPLE(resample_row_8
, GLuint
, 2)
98 RESAMPLE(resample_row_16
, GLuint
, 4)
102 * Blit color, depth or stencil with GL_NEAREST filtering.
105 blit_nearest(GLcontext
*ctx
,
106 GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
107 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
,
110 struct gl_renderbuffer
*readRb
, *drawRb
;
112 const GLint srcWidth
= ABS(srcX1
- srcX0
);
113 const GLint dstWidth
= ABS(dstX1
- dstX0
);
114 const GLint srcHeight
= ABS(srcY1
- srcY0
);
115 const GLint dstHeight
= ABS(dstY1
- dstY0
);
117 const GLint srcXpos
= MIN2(srcX0
, srcX1
);
118 const GLint srcYpos
= MIN2(srcY0
, srcY1
);
119 const GLint dstXpos
= MIN2(dstX0
, dstX1
);
120 const GLint dstYpos
= MIN2(dstY0
, dstY1
);
122 const GLboolean invertX
= (srcX1
< srcX0
) ^ (dstX1
< dstX0
);
123 const GLboolean invertY
= (srcY1
< srcY0
) ^ (dstY1
< dstY0
);
127 GLint comps
, pixelSize
;
128 GLvoid
*srcBuffer
, *dstBuffer
;
131 typedef void (*resample_func
)(GLint srcWidth
, GLint dstWidth
,
132 const GLvoid
*srcBuffer
, GLvoid
*dstBuffer
,
134 resample_func resampleRow
;
137 case GL_COLOR_BUFFER_BIT
:
138 readRb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
139 drawRb
= ctx
->DrawBuffer
->_ColorDrawBuffers
[0];
142 case GL_DEPTH_BUFFER_BIT
:
143 readRb
= ctx
->ReadBuffer
->_DepthBuffer
;
144 drawRb
= ctx
->DrawBuffer
->_DepthBuffer
;
147 case GL_STENCIL_BUFFER_BIT
:
148 readRb
= ctx
->ReadBuffer
->_StencilBuffer
;
149 drawRb
= ctx
->DrawBuffer
->_StencilBuffer
;
153 _mesa_problem(ctx
, "unexpected buffer in blit_nearest()");
157 switch (readRb
->DataType
) {
158 case GL_UNSIGNED_BYTE
:
159 pixelSize
= comps
* sizeof(GLubyte
);
161 case GL_UNSIGNED_SHORT
:
162 pixelSize
= comps
* sizeof(GLushort
);
164 case GL_UNSIGNED_INT
:
165 pixelSize
= comps
* sizeof(GLuint
);
168 pixelSize
= comps
* sizeof(GLfloat
);
171 _mesa_problem(ctx
, "unexpected buffer type (0x%x) in blit_nearest",
176 /* choose row resampler */
179 resampleRow
= resample_row_1
;
182 resampleRow
= resample_row_2
;
185 resampleRow
= resample_row_4
;
188 resampleRow
= resample_row_8
;
191 resampleRow
= resample_row_16
;
194 _mesa_problem(ctx
, "unexpected pixel size (%d) in blit_nearest",
199 /* allocate the src/dst row buffers */
200 srcBuffer
= _mesa_malloc(pixelSize
* srcWidth
);
202 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
205 dstBuffer
= _mesa_malloc(pixelSize
* dstWidth
);
207 _mesa_free(srcBuffer
);
208 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
212 for (dstRow
= 0; dstRow
< dstHeight
; dstRow
++) {
213 const GLint dstY
= dstYpos
+ dstRow
;
214 GLint srcRow
= (dstRow
* srcHeight
) / dstHeight
;
218 ASSERT(srcRow
< srcHeight
);
221 srcRow
= srcHeight
- 1 - srcRow
;
224 srcY
= srcYpos
+ srcRow
;
226 /* get pixel row from source and resample to match dest width */
228 readRb
->GetRow(ctx
, readRb
, srcWidth
, srcXpos
, srcY
, srcBuffer
);
229 (*resampleRow
)(srcWidth
, dstWidth
, srcBuffer
, dstBuffer
, invertX
);
233 /* store pixel row in destination */
234 drawRb
->PutRow(ctx
, drawRb
, dstWidth
, dstXpos
, dstY
, dstBuffer
, NULL
);
237 _mesa_free(srcBuffer
);
238 _mesa_free(dstBuffer
);
243 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
245 static INLINE GLfloat
246 lerp_2d(GLfloat a
, GLfloat b
,
247 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
249 const GLfloat temp0
= LERP(a
, v00
, v10
);
250 const GLfloat temp1
= LERP(a
, v01
, v11
);
251 return LERP(b
, temp0
, temp1
);
256 * Bilinear interpolation of two source rows.
260 resample_linear_row_ub(GLint srcWidth
, GLint dstWidth
,
261 const GLvoid
*srcBuffer0
, const GLvoid
*srcBuffer1
,
262 GLvoid
*dstBuffer
, GLboolean flip
, GLfloat rowWeight
)
264 const GLubyte (*srcColor0
)[4] = (const GLubyte (*)[4]) srcBuffer0
;
265 const GLubyte (*srcColor1
)[4] = (const GLubyte (*)[4]) srcBuffer1
;
266 GLubyte (*dstColor
)[4] = (GLubyte (*)[4]) dstBuffer
;
267 const GLfloat dstWidthF
= (GLfloat
) dstWidth
;
270 for (dstCol
= 0; dstCol
< dstWidth
; dstCol
++) {
271 const GLfloat srcCol
= (dstCol
* srcWidth
) / dstWidthF
;
272 GLint srcCol0
= IFLOOR(srcCol
);
273 GLint srcCol1
= srcCol0
+ 1;
274 GLfloat colWeight
= srcCol
- srcCol0
; /* fractional part of srcCol */
275 GLfloat red
, green
, blue
, alpha
;
277 ASSERT(srcCol0
>= 0);
278 ASSERT(srcCol0
< srcWidth
);
279 ASSERT(srcCol1
<= srcWidth
);
281 if (srcCol1
== srcWidth
) {
282 /* last column fudge */
288 srcCol0
= srcWidth
- 1 - srcCol0
;
289 srcCol1
= srcWidth
- 1 - srcCol1
;
292 red
= lerp_2d(colWeight
, rowWeight
,
293 srcColor0
[srcCol0
][RCOMP
], srcColor0
[srcCol1
][RCOMP
],
294 srcColor1
[srcCol0
][RCOMP
], srcColor1
[srcCol1
][RCOMP
]);
295 green
= lerp_2d(colWeight
, rowWeight
,
296 srcColor0
[srcCol0
][GCOMP
], srcColor0
[srcCol1
][GCOMP
],
297 srcColor1
[srcCol0
][GCOMP
], srcColor1
[srcCol1
][GCOMP
]);
298 blue
= lerp_2d(colWeight
, rowWeight
,
299 srcColor0
[srcCol0
][BCOMP
], srcColor0
[srcCol1
][BCOMP
],
300 srcColor1
[srcCol0
][BCOMP
], srcColor1
[srcCol1
][BCOMP
]);
301 alpha
= lerp_2d(colWeight
, rowWeight
,
302 srcColor0
[srcCol0
][ACOMP
], srcColor0
[srcCol1
][ACOMP
],
303 srcColor1
[srcCol0
][ACOMP
], srcColor1
[srcCol1
][ACOMP
]);
305 dstColor
[dstCol
][RCOMP
] = IFLOOR(red
);
306 dstColor
[dstCol
][GCOMP
] = IFLOOR(green
);
307 dstColor
[dstCol
][BCOMP
] = IFLOOR(blue
);
308 dstColor
[dstCol
][ACOMP
] = IFLOOR(alpha
);
315 * Bilinear filtered blit (color only).
318 blit_linear(GLcontext
*ctx
,
319 GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
320 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
)
322 struct gl_renderbuffer
*readRb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
323 struct gl_renderbuffer
*drawRb
= ctx
->DrawBuffer
->_ColorDrawBuffers
[0];
325 const GLint srcWidth
= ABS(srcX1
- srcX0
);
326 const GLint dstWidth
= ABS(dstX1
- dstX0
);
327 const GLint srcHeight
= ABS(srcY1
- srcY0
);
328 const GLint dstHeight
= ABS(dstY1
- dstY0
);
329 const GLfloat dstHeightF
= (GLfloat
) dstHeight
;
331 const GLint srcXpos
= MIN2(srcX0
, srcX1
);
332 const GLint srcYpos
= MIN2(srcY0
, srcY1
);
333 const GLint dstXpos
= MIN2(dstX0
, dstX1
);
334 const GLint dstYpos
= MIN2(dstY0
, dstY1
);
336 const GLboolean invertX
= (srcX1
< srcX0
) ^ (dstX1
< dstX0
);
337 const GLboolean invertY
= (srcY1
< srcY0
) ^ (dstY1
< dstY0
);
342 GLvoid
*srcBuffer0
, *srcBuffer1
;
343 GLint srcBufferY0
= -1, srcBufferY1
= -1;
346 switch (readRb
->DataType
) {
347 case GL_UNSIGNED_BYTE
:
348 pixelSize
= 4 * sizeof(GLubyte
);
350 case GL_UNSIGNED_SHORT
:
351 pixelSize
= 4 * sizeof(GLushort
);
353 case GL_UNSIGNED_INT
:
354 pixelSize
= 4 * sizeof(GLuint
);
357 pixelSize
= 4 * sizeof(GLfloat
);
360 _mesa_problem(ctx
, "unexpected buffer type (0x%x) in blit_nearest",
365 /* Allocate the src/dst row buffers.
366 * Keep two adjacent src rows around for bilinear sampling.
368 srcBuffer0
= _mesa_malloc(pixelSize
* srcWidth
);
370 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
373 srcBuffer1
= _mesa_malloc(pixelSize
* srcWidth
);
375 _mesa_free(srcBuffer0
);
376 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
379 dstBuffer
= _mesa_malloc(pixelSize
* dstWidth
);
381 _mesa_free(srcBuffer0
);
382 _mesa_free(srcBuffer1
);
383 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
387 for (dstRow
= 0; dstRow
< dstHeight
; dstRow
++) {
388 const GLint dstY
= dstYpos
+ dstRow
;
389 const GLfloat srcRow
= (dstRow
* srcHeight
) / dstHeightF
;
390 GLint srcRow0
= IFLOOR(srcRow
);
391 GLint srcRow1
= srcRow0
+ 1;
392 GLfloat rowWeight
= srcRow
- srcRow0
; /* fractional part of srcRow */
395 ASSERT(srcRow
< srcHeight
);
397 if (srcRow1
== srcHeight
) {
404 srcRow0
= srcHeight
- 1 - srcRow0
;
405 srcRow1
= srcHeight
- 1 - srcRow1
;
408 srcY0
= srcYpos
+ srcRow0
;
409 srcY1
= srcYpos
+ srcRow1
;
411 /* get the two source rows */
412 if (srcY0
== srcBufferY0
&& srcY1
== srcBufferY1
) {
413 /* use same source row buffers again */
415 else if (srcY0
== srcBufferY1
) {
416 /* move buffer1 into buffer0 by swapping pointers */
417 GLvoid
*tmp
= srcBuffer0
;
418 srcBuffer0
= srcBuffer1
;
421 readRb
->GetRow(ctx
, readRb
, srcWidth
, srcXpos
, srcY1
, srcBuffer1
);
426 /* get both new rows */
427 readRb
->GetRow(ctx
, readRb
, srcWidth
, srcXpos
, srcY0
, srcBuffer0
);
428 readRb
->GetRow(ctx
, readRb
, srcWidth
, srcXpos
, srcY1
, srcBuffer1
);
433 if (readRb
->DataType
== GL_UNSIGNED_BYTE
) {
434 resample_linear_row_ub(srcWidth
, dstWidth
, srcBuffer0
, srcBuffer1
,
435 dstBuffer
, invertX
, rowWeight
);
438 _mesa_problem(ctx
, "Unsupported color channel type in sw blit");
442 /* store pixel row in destination */
443 drawRb
->PutRow(ctx
, drawRb
, dstWidth
, dstXpos
, dstY
, dstBuffer
, NULL
);
446 _mesa_free(srcBuffer0
);
447 _mesa_free(srcBuffer1
);
448 _mesa_free(dstBuffer
);
453 * Simple case: Blit color, depth or stencil with no scaling or flipping.
454 * XXX we could easily support vertical flipping here.
457 simple_blit(GLcontext
*ctx
,
458 GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
459 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
,
462 struct gl_renderbuffer
*readRb
, *drawRb
;
463 const GLint width
= srcX1
- srcX0
;
464 const GLint height
= srcY1
- srcY0
;
465 GLint row
, srcY
, dstY
, yStep
;
466 GLint comps
, bytesPerRow
;
469 /* only one buffer */
470 ASSERT(_mesa_bitcount(buffer
) == 1);
471 /* no flipping checks */
472 ASSERT(srcX0
< srcX1
);
473 ASSERT(srcY0
< srcY1
);
474 ASSERT(dstX0
< dstX1
);
475 ASSERT(dstY0
< dstY1
);
477 ASSERT(srcX1
- srcX0
== dstX1
- dstX0
);
478 ASSERT(srcY1
- srcY0
== dstY1
- dstY0
);
480 /* determine if copy should be bottom-to-top or top-to-bottom */
482 /* src above dst: copy bottom-to-top */
488 /* src below dst: copy top-to-bottom */
495 case GL_COLOR_BUFFER_BIT
:
496 readRb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
497 drawRb
= ctx
->DrawBuffer
->_ColorDrawBuffers
[0];
500 case GL_DEPTH_BUFFER_BIT
:
501 readRb
= ctx
->ReadBuffer
->_DepthBuffer
;
502 drawRb
= ctx
->DrawBuffer
->_DepthBuffer
;
505 case GL_STENCIL_BUFFER_BIT
:
506 readRb
= ctx
->ReadBuffer
->_StencilBuffer
;
507 drawRb
= ctx
->DrawBuffer
->_StencilBuffer
;
511 _mesa_problem(ctx
, "unexpected buffer in simple_blit()");
515 ASSERT(readRb
->DataType
== drawRb
->DataType
);
517 /* compute bytes per row */
518 switch (readRb
->DataType
) {
519 case GL_UNSIGNED_BYTE
:
520 bytesPerRow
= comps
* width
* sizeof(GLubyte
);
522 case GL_UNSIGNED_SHORT
:
523 bytesPerRow
= comps
* width
* sizeof(GLushort
);
525 case GL_UNSIGNED_INT
:
526 bytesPerRow
= comps
* width
* sizeof(GLuint
);
529 bytesPerRow
= comps
* width
* sizeof(GLfloat
);
532 _mesa_problem(ctx
, "unexpected buffer type in simple_blit");
536 /* allocate the row buffer */
537 rowBuffer
= _mesa_malloc(bytesPerRow
);
539 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBlitFrameBufferEXT");
543 for (row
= 0; row
< height
; row
++) {
544 readRb
->GetRow(ctx
, readRb
, width
, srcX0
, srcY
, rowBuffer
);
545 drawRb
->PutRow(ctx
, drawRb
, width
, dstX0
, dstY
, rowBuffer
, NULL
);
550 _mesa_free(rowBuffer
);
555 * Software fallback for glBlitFramebufferEXT().
558 _swrast_BlitFramebuffer(GLcontext
*ctx
,
559 GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
560 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
,
561 GLbitfield mask
, GLenum filter
)
563 static const GLbitfield buffers
[3] = {
566 GL_STENCIL_BUFFER_BIT
570 if (!ctx
->DrawBuffer
->_NumColorDrawBuffers
)
573 if (!_mesa_clip_blit(ctx
, &srcX0
, &srcY0
, &srcX1
, &srcY1
,
574 &dstX0
, &dstY0
, &dstX1
, &dstY1
)) {
578 swrast_render_start(ctx
);
580 if (srcX1
- srcX0
== dstX1
- dstX0
&&
581 srcY1
- srcY0
== dstY1
- dstY0
&&
586 /* no stretching or flipping.
587 * filter doesn't matter.
589 for (i
= 0; i
< 3; i
++) {
590 if (mask
& buffers
[i
]) {
591 simple_blit(ctx
, srcX0
, srcY0
, srcX1
, srcY1
,
592 dstX0
, dstY0
, dstX1
, dstY1
, buffers
[i
]);
597 if (filter
== GL_NEAREST
) {
598 for (i
= 0; i
< 3; i
++) {
599 if (mask
& buffers
[i
]) {
600 blit_nearest(ctx
, srcX0
, srcY0
, srcX1
, srcY1
,
601 dstX0
, dstY0
, dstX1
, dstY1
, buffers
[i
]);
606 ASSERT(filter
== GL_LINEAR
);
607 if (mask
& GL_COLOR_BUFFER_BIT
) { /* depth/stencil not allowed */
608 blit_linear(ctx
, srcX0
, srcY0
, srcX1
, srcY1
,
609 dstX0
, dstY0
, dstX1
, dstY1
);
614 swrast_render_finish(ctx
);