2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
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 = NULL;
114 struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL;
115 struct gl_framebuffer *readFb = ctx->ReadBuffer;
116 struct gl_framebuffer *drawFb = ctx->DrawBuffer;
117 GLuint numDrawBuffers = 0;
120 const GLint srcWidth = ABS(srcX1 - srcX0);
121 const GLint dstWidth = ABS(dstX1 - dstX0);
122 const GLint srcHeight = ABS(srcY1 - srcY0);
123 const GLint dstHeight = ABS(dstY1 - dstY0);
125 const GLint srcXpos = MIN2(srcX0, srcX1);
126 const GLint srcYpos = MIN2(srcY0, srcY1);
127 const GLint dstXpos = MIN2(dstX0, dstX1);
128 const GLint dstYpos = MIN2(dstY0, dstY1);
130 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
131 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
139 GLubyte *srcMap, *dstMap;
140 GLint srcRowStride, dstRowStride;
144 GLvoid *srcBuffer, *dstBuffer;
147 typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
148 const GLvoid *srcBuffer, GLvoid *dstBuffer,
150 resample_func resampleRow;
153 case GL_COLOR_BUFFER_BIT:
154 readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
155 readRb = readFb->_ColorReadBuffer;
156 numDrawBuffers = drawFb->_NumColorDrawBuffers;
158 case GL_DEPTH_BUFFER_BIT:
159 readAtt = &readFb->Attachment[BUFFER_DEPTH];
160 drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
161 readRb = readAtt->Renderbuffer;
162 drawRb = drawAtt->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 readAtt = &readFb->Attachment[BUFFER_STENCIL];
179 drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
180 readRb = readAtt->Renderbuffer;
181 drawRb = drawAtt->Renderbuffer;
187 _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
191 /* allocate the src/dst row buffers */
192 srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth);
193 dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth);
194 if (!srcBuffer || !dstBuffer)
197 /* Blit to all the draw buffers */
198 for (i = 0; i < numDrawBuffers; i++) {
199 if (buffer == GL_COLOR_BUFFER_BIT) {
200 int idx = drawFb->_ColorDrawBufferIndexes[i];
203 drawAtt = &drawFb->Attachment[idx];
204 drawRb = drawAtt->Renderbuffer;
209 if (readRb->Format == drawRb->Format) {
211 pixelSize = _mesa_get_format_bytes(readRb->Format);
213 mode = UNPACK_RGBA_FLOAT;
218 /* choose row resampler */
221 resampleRow = resample_row_1;
224 resampleRow = resample_row_2;
227 resampleRow = resample_row_4;
230 resampleRow = resample_row_8;
233 resampleRow = resample_row_16;
236 _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
241 if ((readRb == drawRb) ||
242 (readAtt->Texture && drawAtt->Texture &&
243 (readAtt->Texture == drawAtt->Texture))) {
244 /* map whole buffer for read/write */
245 /* XXX we could be clever and just map the union region of the
246 * source and dest rects.
250 GLint formatSize = _mesa_get_format_bytes(readRb->Format);
252 ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
253 readRb->Width, readRb->Height,
254 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
260 srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
261 dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
263 /* this handles overlapping copies */
265 /* copy in reverse (top->down) order */
266 srcMap += rowStride * (readRb->Height - 1);
267 dstMap += rowStride * (readRb->Height - 1);
268 srcRowStride = -rowStride;
269 dstRowStride = -rowStride;
272 /* copy in normal (bottom->up) order */
273 srcRowStride = rowStride;
274 dstRowStride = rowStride;
278 /* different src/dst buffers */
279 ctx->Driver.MapRenderbuffer(ctx, readRb,
282 GL_MAP_READ_BIT, &srcMap, &srcRowStride);
286 ctx->Driver.MapRenderbuffer(ctx, drawRb,
289 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
291 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
296 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
297 GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
298 GLint srcRow = IROUND(srcRowF);
299 GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
302 ASSERT(srcRow < srcHeight);
305 srcRow = srcHeight - 1 - srcRow;
308 /* get pixel row from source and resample to match dest width */
309 if (prevY != srcRow) {
310 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
314 memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
316 case UNPACK_RGBA_FLOAT:
317 _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
321 _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
325 _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
329 _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
330 srcRowStart, srcBuffer);
334 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
338 /* store pixel row in destination */
341 memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
343 case UNPACK_RGBA_FLOAT:
344 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
348 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
352 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
356 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
362 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
363 if (drawRb != readRb) {
364 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
376 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
381 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
383 static inline GLfloat
384 lerp_2d(GLfloat a, GLfloat b,
385 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
387 const GLfloat temp0 = LERP(a, v00, v10);
388 const GLfloat temp1 = LERP(a, v01, v11);
389 return LERP(b, temp0, temp1);
394 * Bilinear interpolation of two source rows.
398 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
399 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
400 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
402 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
403 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
404 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
407 for (dstCol = 0; dstCol < dstWidth; dstCol++) {
408 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
409 GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
410 GLint srcCol1 = srcCol0 + 1;
411 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
412 GLfloat red, green, blue, alpha;
414 ASSERT(srcCol0 < srcWidth);
415 ASSERT(srcCol1 <= srcWidth);
417 if (srcCol1 == srcWidth) {
418 /* last column fudge */
424 srcCol0 = srcWidth - 1 - srcCol0;
425 srcCol1 = srcWidth - 1 - srcCol1;
428 red = lerp_2d(colWeight, rowWeight,
429 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
430 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
431 green = lerp_2d(colWeight, rowWeight,
432 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
433 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
434 blue = lerp_2d(colWeight, rowWeight,
435 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
436 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
437 alpha = lerp_2d(colWeight, rowWeight,
438 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
439 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
441 dstColor[dstCol][RCOMP] = IFLOOR(red);
442 dstColor[dstCol][GCOMP] = IFLOOR(green);
443 dstColor[dstCol][BCOMP] = IFLOOR(blue);
444 dstColor[dstCol][ACOMP] = IFLOOR(alpha);
450 * Bilinear interpolation of two source rows. floating point pixels.
453 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
454 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
455 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
457 const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
458 const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
459 GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
462 for (dstCol = 0; dstCol < dstWidth; dstCol++) {
463 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
464 GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
465 GLint srcCol1 = srcCol0 + 1;
466 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
467 GLfloat red, green, blue, alpha;
469 ASSERT(srcCol0 < srcWidth);
470 ASSERT(srcCol1 <= srcWidth);
472 if (srcCol1 == srcWidth) {
473 /* last column fudge */
479 srcCol0 = srcWidth - 1 - srcCol0;
480 srcCol1 = srcWidth - 1 - srcCol1;
483 red = lerp_2d(colWeight, rowWeight,
484 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
485 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
486 green = lerp_2d(colWeight, rowWeight,
487 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
488 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
489 blue = lerp_2d(colWeight, rowWeight,
490 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
491 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
492 alpha = lerp_2d(colWeight, rowWeight,
493 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
494 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
496 dstColor[dstCol][RCOMP] = red;
497 dstColor[dstCol][GCOMP] = green;
498 dstColor[dstCol][BCOMP] = blue;
499 dstColor[dstCol][ACOMP] = alpha;
506 * Bilinear filtered blit (color only, non-integer values).
509 blit_linear(struct gl_context *ctx,
510 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
511 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
513 struct gl_framebuffer *drawFb = ctx->DrawBuffer;
514 struct gl_framebuffer *readFb = ctx->ReadBuffer;
515 struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
516 struct gl_renderbuffer_attachment *readAtt =
517 &readFb->Attachment[readFb->_ColorReadBufferIndex];
519 const GLint srcWidth = ABS(srcX1 - srcX0);
520 const GLint dstWidth = ABS(dstX1 - dstX0);
521 const GLint srcHeight = ABS(srcY1 - srcY0);
522 const GLint dstHeight = ABS(dstY1 - dstY0);
524 const GLint srcXpos = MIN2(srcX0, srcX1);
525 const GLint srcYpos = MIN2(srcY0, srcY1);
526 const GLint dstXpos = MIN2(dstX0, dstX1);
527 const GLint dstYpos = MIN2(dstY0, dstY1);
529 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
530 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
535 GLvoid *srcBuffer0, *srcBuffer1;
536 GLint srcBufferY0 = -1, srcBufferY1 = -1;
539 gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
540 GLuint bpp = _mesa_get_format_bytes(readFormat);
544 GLubyte *srcMap, *dstMap;
545 GLint srcRowStride, dstRowStride;
549 /* Determine datatype for resampling */
550 if (_mesa_get_format_max_bits(readFormat) == 8 &&
551 _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
552 pixelType = GL_UNSIGNED_BYTE;
553 pixelSize = 4 * sizeof(GLubyte);
556 pixelType = GL_FLOAT;
557 pixelSize = 4 * sizeof(GLfloat);
560 /* Allocate the src/dst row buffers.
561 * Keep two adjacent src rows around for bilinear sampling.
563 srcBuffer0 = malloc(pixelSize * srcWidth);
564 srcBuffer1 = malloc(pixelSize * srcWidth);
565 dstBuffer = malloc(pixelSize * dstWidth);
566 if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
570 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
571 GLint idx = drawFb->_ColorDrawBufferIndexes[i];
572 struct gl_renderbuffer_attachment *drawAtt;
573 struct gl_renderbuffer *drawRb;
574 gl_format drawFormat;
579 drawAtt = &drawFb->Attachment[idx];
580 drawRb = drawAtt->Renderbuffer;
584 drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
587 * Map src / dst renderbuffers
589 if ((readRb == drawRb) ||
590 (readAtt->Texture && drawAtt->Texture &&
591 (readAtt->Texture == drawAtt->Texture))) {
592 /* map whole buffer for read/write */
593 ctx->Driver.MapRenderbuffer(ctx, readRb,
594 0, 0, readRb->Width, readRb->Height,
595 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
596 &srcMap, &srcRowStride);
602 dstRowStride = srcRowStride;
605 /* different src/dst buffers */
606 /* XXX with a bit of work we could just map the regions to be
607 * read/written instead of the whole buffers.
609 ctx->Driver.MapRenderbuffer(ctx, readRb,
610 0, 0, readRb->Width, readRb->Height,
611 GL_MAP_READ_BIT, &srcMap, &srcRowStride);
615 ctx->Driver.MapRenderbuffer(ctx, drawRb,
616 0, 0, drawRb->Width, drawRb->Height,
617 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
619 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
624 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
625 const GLint dstY = dstYpos + dstRow;
626 GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
627 GLint srcRow0 = MAX2(0, IFLOOR(srcRow));
628 GLint srcRow1 = srcRow0 + 1;
629 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
631 if (srcRow1 == srcHeight) {
638 srcRow0 = srcHeight - 1 - srcRow0;
639 srcRow1 = srcHeight - 1 - srcRow1;
642 srcY0 = srcYpos + srcRow0;
643 srcY1 = srcYpos + srcRow1;
645 /* get the two source rows */
646 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
647 /* use same source row buffers again */
649 else if (srcY0 == srcBufferY1) {
650 /* move buffer1 into buffer0 by swapping pointers */
651 GLvoid *tmp = srcBuffer0;
652 srcBuffer0 = srcBuffer1;
656 GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
657 if (pixelType == GL_UNSIGNED_BYTE) {
658 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
662 _mesa_unpack_rgba_row(readFormat, srcWidth,
670 /* get both new rows */
672 GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
673 GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
674 if (pixelType == GL_UNSIGNED_BYTE) {
675 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
677 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
681 _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
682 _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
689 if (pixelType == GL_UNSIGNED_BYTE) {
690 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
691 dstBuffer, invertX, rowWeight);
694 resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
695 dstBuffer, invertX, rowWeight);
698 /* store pixel row in destination */
700 GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
701 if (pixelType == GL_UNSIGNED_BYTE) {
702 _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
705 _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
710 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
711 if (drawRb != readRb) {
712 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
725 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
731 * Software fallback for glBlitFramebufferEXT().
734 _swrast_BlitFramebuffer(struct gl_context *ctx,
735 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
736 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
737 GLbitfield mask, GLenum filter)
739 static const GLbitfield buffers[3] = {
742 GL_STENCIL_BUFFER_BIT
744 static const GLenum buffer_enums[3] = {
751 if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
752 &dstX0, &dstY0, &dstX1, &dstY1)) {
756 if (SWRAST_CONTEXT(ctx)->NewState)
757 _swrast_validate_derived(ctx);
759 /* First, try covering whatever buffers possible using the fast 1:1 copy
762 if (srcX1 - srcX0 == dstX1 - dstX0 &&
763 srcY1 - srcY0 == dstY1 - dstY0 &&
768 for (i = 0; i < 3; i++) {
769 if (mask & buffers[i]) {
770 if (swrast_fast_copy_pixels(ctx,
772 srcX1 - srcX0, srcY1 - srcY0,
784 if (filter == GL_NEAREST) {
785 for (i = 0; i < 3; i++) {
786 if (mask & buffers[i]) {
787 blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1,
788 dstX0, dstY0, dstX1, dstY1, buffers[i]);
793 ASSERT(filter == GL_LINEAR);
794 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */
795 blit_linear(ctx, srcX0, srcY0, srcX1, srcY1,
796 dstX0, dstY0, dstX1, dstY1);