1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
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 "s_context.h"
33
34
35 #define ABS(X) ((X) < 0 ? -(X) : (X))
36
37
38 /**
39 * Generate a row resampler function for GL_NEAREST mode.
40 */
41 #define RESAMPLE(NAME, PIXELTYPE, SIZE) \
42 static void \
43 NAME(GLint srcWidth, GLint dstWidth, \
44 const GLvoid *srcBuffer, GLvoid *dstBuffer, \
45 GLboolean flip) \
46 { \
47 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
48 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \
49 GLint dstCol; \
50 \
51 if (flip) { \
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 */ \
57 if (SIZE == 1) { \
58 dst[dstCol] = src[srcCol]; \
59 } \
60 else if (SIZE == 2) { \
61 dst[dstCol*2+0] = src[srcCol*2+0]; \
62 dst[dstCol*2+1] = src[srcCol*2+1]; \
63 } \
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]; \
69 } \
70 } \
71 } \
72 else { \
73 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
74 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
75 ASSERT(srcCol >= 0); \
76 ASSERT(srcCol < srcWidth); \
77 if (SIZE == 1) { \
78 dst[dstCol] = src[srcCol]; \
79 } \
80 else if (SIZE == 2) { \
81 dst[dstCol*2+0] = src[srcCol*2+0]; \
82 dst[dstCol*2+1] = src[srcCol*2+1]; \
83 } \
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]; \
89 } \
90 } \
91 } \
92 }
93
94 /**
95 * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
96 */
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)
102
103
104 /**
105 * Blit color, depth or stencil with GL_NEAREST filtering.
106 */
107 static void
blit_nearest(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield buffer)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,
111 GLbitfield buffer)
112 {
113 struct gl_renderbuffer *readRb, *drawRb;
114
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);
119
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);
124
125 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
126 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
127 enum mode {
128 DIRECT,
129 UNPACK_RGBA_FLOAT,
130 UNPACK_Z_FLOAT,
131 UNPACK_Z_INT,
132 UNPACK_S,
133 } mode;
134 GLubyte *srcMap, *dstMap;
135 GLint srcRowStride, dstRowStride;
136 GLint dstRow;
137
138 GLint pixelSize;
139 GLvoid *srcBuffer, *dstBuffer;
140 GLint prevY = -1;
141
142 typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
143 const GLvoid *srcBuffer, GLvoid *dstBuffer,
144 GLboolean flip);
145 resample_func resampleRow;
146
147 switch (buffer) {
148 case GL_COLOR_BUFFER_BIT:
149 readRb = ctx->ReadBuffer->_ColorReadBuffer;
150 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
151
152 if (readRb->Format == drawRb->Format) {
153 mode = DIRECT;
154 pixelSize = _mesa_get_format_bytes(readRb->Format);
155 } else {
156 mode = UNPACK_RGBA_FLOAT;
157 pixelSize = 16;
158 }
159
160 break;
161 case GL_DEPTH_BUFFER_BIT:
162 readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
163 drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
164
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.
168 */
169 if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
170 readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
171 mode = UNPACK_Z_FLOAT;
172 } else {
173 mode = UNPACK_Z_INT;
174 }
175 pixelSize = 4;
176 break;
177 case GL_STENCIL_BUFFER_BIT:
178 readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
179 drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
180 mode = UNPACK_S;
181 pixelSize = 1;
182 break;
183 default:
184 _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
185 return;
186 }
187
188 /* choose row resampler */
189 switch (pixelSize) {
190 case 1:
191 resampleRow = resample_row_1;
192 break;
193 case 2:
194 resampleRow = resample_row_2;
195 break;
196 case 4:
197 resampleRow = resample_row_4;
198 break;
199 case 8:
200 resampleRow = resample_row_8;
201 break;
202 case 16:
203 resampleRow = resample_row_16;
204 break;
205 default:
206 _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
207 pixelSize);
208 return;
209 }
210
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.
215 */
216 GLubyte *map;
217 GLint rowStride;
218 GLint formatSize = _mesa_get_format_bytes(readRb->Format);
219
220 ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
221 readRb->Width, readRb->Height,
222 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
223 &map, &rowStride);
224 if (!map) {
225 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
226 return;
227 }
228
229 srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
230 dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
231
232 /* this handles overlapping copies */
233 if (srcY0 < dstY0) {
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;
239 }
240 else {
241 /* copy in normal (bottom->up) order */
242 srcRowStride = rowStride;
243 dstRowStride = rowStride;
244 }
245 }
246 else {
247 /* different src/dst buffers */
248 ctx->Driver.MapRenderbuffer(ctx, readRb,
249 srcXpos, srcYpos,
250 srcWidth, srcHeight,
251 GL_MAP_READ_BIT, &srcMap, &srcRowStride);
252 if (!srcMap) {
253 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
254 return;
255 }
256 ctx->Driver.MapRenderbuffer(ctx, drawRb,
257 dstXpos, dstYpos,
258 dstWidth, dstHeight,
259 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
260 if (!dstMap) {
261 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
262 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
263 return;
264 }
265 }
266
267 /* allocate the src/dst row buffers */
268 srcBuffer = malloc(pixelSize * srcWidth);
269 if (!srcBuffer) {
270 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
271 return;
272 }
273 dstBuffer = malloc(pixelSize * dstWidth);
274 if (!dstBuffer) {
275 free(srcBuffer);
276 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
277 return;
278 }
279
280 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
281 GLint srcRow = (dstRow * srcHeight) / dstHeight;
282 GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
283
284 ASSERT(srcRow >= 0);
285 ASSERT(srcRow < srcHeight);
286
287 if (invertY) {
288 srcRow = srcHeight - 1 - srcRow;
289 }
290
291 /* get pixel row from source and resample to match dest width */
292 if (prevY != srcRow) {
293 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
294
295 switch (mode) {
296 case DIRECT:
297 memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
298 break;
299 case UNPACK_RGBA_FLOAT:
300 _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
301 srcBuffer);
302 break;
303 case UNPACK_Z_FLOAT:
304 _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
305 srcBuffer);
306 break;
307 case UNPACK_Z_INT:
308 _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
309 srcBuffer);
310 break;
311 case UNPACK_S:
312 _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
313 srcRowStart, srcBuffer);
314 break;
315 }
316
317 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
318 prevY = srcRow;
319 }
320
321 /* store pixel row in destination */
322 switch (mode) {
323 case DIRECT:
324 memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
325 break;
326 case UNPACK_RGBA_FLOAT:
327 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
328 dstRowStart);
329 break;
330 case UNPACK_Z_FLOAT:
331 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
332 dstRowStart);
333 break;
334 case UNPACK_Z_INT:
335 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
336 dstRowStart);
337 break;
338 case UNPACK_S:
339 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
340 dstRowStart);
341 break;
342 }
343 }
344
345 free(srcBuffer);
346 free(dstBuffer);
347
348 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
349 if (drawRb != readRb) {
350 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
351 }
352 }
353
354
355
356 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
357
358 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)359 lerp_2d(GLfloat a, GLfloat b,
360 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
361 {
362 const GLfloat temp0 = LERP(a, v00, v10);
363 const GLfloat temp1 = LERP(a, v01, v11);
364 return LERP(b, temp0, temp1);
365 }
366
367
368 /**
369 * Bilinear interpolation of two source rows.
370 * GLubyte pixels.
371 */
372 static void
resample_linear_row_ub(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)373 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
374 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
375 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
376 {
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;
381 GLint dstCol;
382
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;
389
390 ASSERT(srcCol0 >= 0);
391 ASSERT(srcCol0 < srcWidth);
392 ASSERT(srcCol1 <= srcWidth);
393
394 if (srcCol1 == srcWidth) {
395 /* last column fudge */
396 srcCol1--;
397 colWeight = 0.0;
398 }
399
400 if (flip) {
401 srcCol0 = srcWidth - 1 - srcCol0;
402 srcCol1 = srcWidth - 1 - srcCol1;
403 }
404
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]);
417
418 dstColor[dstCol][RCOMP] = IFLOOR(red);
419 dstColor[dstCol][GCOMP] = IFLOOR(green);
420 dstColor[dstCol][BCOMP] = IFLOOR(blue);
421 dstColor[dstCol][ACOMP] = IFLOOR(alpha);
422 }
423 }
424
425
426 /**
427 * Bilinear interpolation of two source rows. floating point pixels.
428 */
429 static void
resample_linear_row_float(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)430 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
431 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
432 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
433 {
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;
438 GLint dstCol;
439
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;
446
447 ASSERT(srcCol0 >= 0);
448 ASSERT(srcCol0 < srcWidth);
449 ASSERT(srcCol1 <= srcWidth);
450
451 if (srcCol1 == srcWidth) {
452 /* last column fudge */
453 srcCol1--;
454 colWeight = 0.0;
455 }
456
457 if (flip) {
458 srcCol0 = srcWidth - 1 - srcCol0;
459 srcCol1 = srcWidth - 1 - srcCol1;
460 }
461
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]);
474
475 dstColor[dstCol][RCOMP] = red;
476 dstColor[dstCol][GCOMP] = green;
477 dstColor[dstCol][BCOMP] = blue;
478 dstColor[dstCol][ACOMP] = alpha;
479 }
480 }
481
482
483
484 /**
485 * Bilinear filtered blit (color only, non-integer values).
486 */
487 static void
blit_linear(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1)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)
491 {
492 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
493 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
494
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;
500
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);
505
506 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
507 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
508
509 GLint dstRow;
510
511 GLint pixelSize;
512 GLvoid *srcBuffer0, *srcBuffer1;
513 GLint srcBufferY0 = -1, srcBufferY1 = -1;
514 GLvoid *dstBuffer;
515
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);
519
520 GLenum pixelType;
521
522 GLubyte *srcMap, *dstMap;
523 GLint srcRowStride, dstRowStride;
524
525
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);
531 }
532 else {
533 pixelType = GL_FLOAT;
534 pixelSize = 4 * sizeof(GLfloat);
535 }
536
537 /* Allocate the src/dst row buffers.
538 * Keep two adjacent src rows around for bilinear sampling.
539 */
540 srcBuffer0 = malloc(pixelSize * srcWidth);
541 if (!srcBuffer0) {
542 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
543 return;
544 }
545 srcBuffer1 = malloc(pixelSize * srcWidth);
546 if (!srcBuffer1) {
547 free(srcBuffer0);
548 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
549 return;
550 }
551 dstBuffer = malloc(pixelSize * dstWidth);
552 if (!dstBuffer) {
553 free(srcBuffer0);
554 free(srcBuffer1);
555 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
556 return;
557 }
558
559 /*
560 * Map src / dst renderbuffers
561 */
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);
568 if (!srcMap) {
569 free(srcBuffer0);
570 free(srcBuffer1);
571 free(dstBuffer);
572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
573 return;
574 }
575
576 dstMap = srcMap;
577 dstRowStride = srcRowStride;
578 }
579 else {
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.
583 */
584 ctx->Driver.MapRenderbuffer(ctx, readRb,
585 0, 0, readRb->Width, readRb->Height,
586 GL_MAP_READ_BIT, &srcMap, &srcRowStride);
587 if (!srcMap) {
588 free(srcBuffer0);
589 free(srcBuffer1);
590 free(dstBuffer);
591 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
592 return;
593 }
594 ctx->Driver.MapRenderbuffer(ctx, drawRb,
595 0, 0, drawRb->Width, drawRb->Height,
596 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
597 if (!dstMap) {
598 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
599 free(srcBuffer0);
600 free(srcBuffer1);
601 free(dstBuffer);
602 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
603 return;
604 }
605 }
606
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 */
613
614 ASSERT(srcRow >= 0);
615 ASSERT(srcRow < srcHeight);
616
617 if (srcRow1 == srcHeight) {
618 /* last row fudge */
619 srcRow1 = srcRow0;
620 rowWeight = 0.0;
621 }
622
623 if (invertY) {
624 srcRow0 = srcHeight - 1 - srcRow0;
625 srcRow1 = srcHeight - 1 - srcRow1;
626 }
627
628 srcY0 = srcYpos + srcRow0;
629 srcY1 = srcYpos + srcRow1;
630
631 /* get the two source rows */
632 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
633 /* use same source row buffers again */
634 }
635 else if (srcY0 == srcBufferY1) {
636 /* move buffer1 into buffer0 by swapping pointers */
637 GLvoid *tmp = srcBuffer0;
638 srcBuffer0 = srcBuffer1;
639 srcBuffer1 = tmp;
640 /* get y1 row */
641 {
642 GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
643 if (pixelType == GL_UNSIGNED_BYTE) {
644 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
645 src, srcBuffer1);
646 }
647 else {
648 _mesa_unpack_rgba_row(readFormat, srcWidth,
649 src, srcBuffer1);
650 }
651 }
652 srcBufferY0 = srcY0;
653 srcBufferY1 = srcY1;
654 }
655 else {
656 /* get both new rows */
657 {
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,
662 src0, srcBuffer0);
663 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
664 src1, srcBuffer1);
665 }
666 else {
667 _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
668 _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
669 }
670 }
671 srcBufferY0 = srcY0;
672 srcBufferY1 = srcY1;
673 }
674
675 if (pixelType == GL_UNSIGNED_BYTE) {
676 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
677 dstBuffer, invertX, rowWeight);
678 }
679 else {
680 resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
681 dstBuffer, invertX, rowWeight);
682 }
683
684 /* store pixel row in destination */
685 {
686 GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
687 if (pixelType == GL_UNSIGNED_BYTE) {
688 _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
689 }
690 else {
691 _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
692 }
693 }
694 }
695
696 free(srcBuffer0);
697 free(srcBuffer1);
698 free(dstBuffer);
699
700 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
701 if (drawRb != readRb) {
702 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
703 }
704 }
705
706
707
708 /**
709 * Software fallback for glBlitFramebufferEXT().
710 */
711 void
_swrast_BlitFramebuffer(struct gl_context * ctx,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)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)
716 {
717 static const GLbitfield buffers[3] = {
718 GL_COLOR_BUFFER_BIT,
719 GL_DEPTH_BUFFER_BIT,
720 GL_STENCIL_BUFFER_BIT
721 };
722 static const GLenum buffer_enums[3] = {
723 GL_COLOR,
724 GL_DEPTH,
725 GL_STENCIL,
726 };
727 GLint i;
728
729 if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
730 &dstX0, &dstY0, &dstX1, &dstY1)) {
731 return;
732 }
733
734 if (SWRAST_CONTEXT(ctx)->NewState)
735 _swrast_validate_derived(ctx);
736
737 /* First, try covering whatever buffers possible using the fast 1:1 copy
738 * path.
739 */
740 if (srcX1 - srcX0 == dstX1 - dstX0 &&
741 srcY1 - srcY0 == dstY1 - dstY0 &&
742 srcX0 < srcX1 &&
743 srcY0 < srcY1 &&
744 dstX0 < dstX1 &&
745 dstY0 < dstY1) {
746 for (i = 0; i < 3; i++) {
747 if (mask & buffers[i]) {
748 if (swrast_fast_copy_pixels(ctx,
749 srcX0, srcY0,
750 srcX1 - srcX0, srcY1 - srcY0,
751 dstX0, dstY0,
752 buffer_enums[i])) {
753 mask &= ~buffers[i];
754 }
755 }
756 }
757
758 if (!mask)
759 return;
760 }
761
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]);
767 }
768 }
769 }
770 else {
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);
775 }
776 }
777
778 }
779