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