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 gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
202 if (idx == BUFFER_NONE)
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, readFb->FlipY);
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 readFb->FlipY);
285 if (!srcMap) {
286 goto fail_no_memory;
287 }
288 ctx->Driver.MapRenderbuffer(ctx, drawRb,
289 dstXpos, dstYpos,
290 dstWidth, dstHeight,
291 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
292 drawFb->FlipY);
293 if (!dstMap) {
294 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
295 goto fail_no_memory;
296 }
297 }
298
299 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
300 GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
301 GLint srcRow = lroundf(srcRowF);
302 GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
303
304 assert(srcRow >= 0);
305 assert(srcRow < srcHeight);
306
307 if (invertY) {
308 srcRow = srcHeight - 1 - srcRow;
309 }
310
311 /* get pixel row from source and resample to match dest width */
312 if (prevY != srcRow) {
313 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
314
315 switch (mode) {
316 case DIRECT:
317 memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
318 break;
319 case UNPACK_RGBA_FLOAT:
320 _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
321 srcBuffer);
322 break;
323 case UNPACK_Z_FLOAT:
324 _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
325 srcBuffer);
326 break;
327 case UNPACK_Z_INT:
328 _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
329 srcBuffer);
330 break;
331 case UNPACK_S:
332 _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
333 srcRowStart, srcBuffer);
334 break;
335 }
336
337 resampleRow(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
338 prevY = srcRow;
339 }
340
341 /* store pixel row in destination */
342 switch (mode) {
343 case DIRECT:
344 memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
345 break;
346 case UNPACK_RGBA_FLOAT:
347 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
348 dstRowStart);
349 break;
350 case UNPACK_Z_FLOAT:
351 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
352 dstRowStart);
353 break;
354 case UNPACK_Z_INT:
355 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
356 dstRowStart);
357 break;
358 case UNPACK_S:
359 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
360 dstRowStart);
361 break;
362 }
363 }
364
365 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
366 if (drawRb != readRb) {
367 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
368 }
369 }
370
371 fail:
372 free(srcBuffer);
373 free(dstBuffer);
374 return;
375
376 fail_no_memory:
377 free(srcBuffer);
378 free(dstBuffer);
379 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
380 }
381
382
383
384 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
385
386 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)387 lerp_2d(GLfloat a, GLfloat b,
388 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
389 {
390 const GLfloat temp0 = LERP(a, v00, v10);
391 const GLfloat temp1 = LERP(a, v01, v11);
392 return LERP(b, temp0, temp1);
393 }
394
395
396 /**
397 * Bilinear interpolation of two source rows.
398 * GLubyte pixels.
399 */
400 static void
resample_linear_row_ub(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)401 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
402 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
403 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
404 {
405 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
406 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
407 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
408 GLint dstCol;
409
410 for (dstCol = 0; dstCol < dstWidth; dstCol++) {
411 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
412 GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
413 GLint srcCol1 = srcCol0 + 1;
414 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
415 GLfloat red, green, blue, alpha;
416
417 assert(srcCol0 < srcWidth);
418 assert(srcCol1 <= srcWidth);
419
420 if (srcCol1 == srcWidth) {
421 /* last column fudge */
422 srcCol1--;
423 colWeight = 0.0;
424 }
425
426 if (flip) {
427 srcCol0 = srcWidth - 1 - srcCol0;
428 srcCol1 = srcWidth - 1 - srcCol1;
429 }
430
431 red = lerp_2d(colWeight, rowWeight,
432 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
433 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
434 green = lerp_2d(colWeight, rowWeight,
435 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
436 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
437 blue = lerp_2d(colWeight, rowWeight,
438 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
439 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
440 alpha = lerp_2d(colWeight, rowWeight,
441 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
442 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
443
444 dstColor[dstCol][RCOMP] = util_ifloor(red);
445 dstColor[dstCol][GCOMP] = util_ifloor(green);
446 dstColor[dstCol][BCOMP] = util_ifloor(blue);
447 dstColor[dstCol][ACOMP] = util_ifloor(alpha);
448 }
449 }
450
451
452 /**
453 * Bilinear interpolation of two source rows. floating point pixels.
454 */
455 static void
resample_linear_row_float(GLint srcWidth,GLint dstWidth,const GLvoid * srcBuffer0,const GLvoid * srcBuffer1,GLvoid * dstBuffer,GLboolean flip,GLfloat rowWeight)456 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
457 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
458 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
459 {
460 const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
461 const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
462 GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
463 GLint dstCol;
464
465 for (dstCol = 0; dstCol < dstWidth; dstCol++) {
466 const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
467 GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
468 GLint srcCol1 = srcCol0 + 1;
469 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
470 GLfloat red, green, blue, alpha;
471
472 assert(srcCol0 < srcWidth);
473 assert(srcCol1 <= srcWidth);
474
475 if (srcCol1 == srcWidth) {
476 /* last column fudge */
477 srcCol1--;
478 colWeight = 0.0;
479 }
480
481 if (flip) {
482 srcCol0 = srcWidth - 1 - srcCol0;
483 srcCol1 = srcWidth - 1 - srcCol1;
484 }
485
486 red = lerp_2d(colWeight, rowWeight,
487 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
488 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
489 green = lerp_2d(colWeight, rowWeight,
490 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
491 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
492 blue = lerp_2d(colWeight, rowWeight,
493 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
494 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
495 alpha = lerp_2d(colWeight, rowWeight,
496 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
497 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
498
499 dstColor[dstCol][RCOMP] = red;
500 dstColor[dstCol][GCOMP] = green;
501 dstColor[dstCol][BCOMP] = blue;
502 dstColor[dstCol][ACOMP] = alpha;
503 }
504 }
505
506
507
508 /**
509 * Bilinear filtered blit (color only, non-integer values).
510 */
511 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)512 blit_linear(struct gl_context *ctx,
513 struct gl_framebuffer *readFb,
514 struct gl_framebuffer *drawFb,
515 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
516 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
517 {
518 struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
519 struct gl_renderbuffer_attachment *readAtt =
520 &readFb->Attachment[readFb->_ColorReadBufferIndex];
521
522 const GLint srcWidth = ABS(srcX1 - srcX0);
523 const GLint dstWidth = ABS(dstX1 - dstX0);
524 const GLint srcHeight = ABS(srcY1 - srcY0);
525 const GLint dstHeight = ABS(dstY1 - dstY0);
526
527 const GLint srcXpos = MIN2(srcX0, srcX1);
528 const GLint srcYpos = MIN2(srcY0, srcY1);
529 const GLint dstXpos = MIN2(dstX0, dstX1);
530 const GLint dstYpos = MIN2(dstY0, dstY1);
531
532 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
533 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
534
535 GLint dstRow;
536
537 GLint pixelSize;
538 GLvoid *srcBuffer0, *srcBuffer1;
539 GLint srcBufferY0 = -1, srcBufferY1 = -1;
540 GLvoid *dstBuffer;
541
542 mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
543 GLuint bpp = _mesa_get_format_bytes(readFormat);
544
545 GLenum pixelType;
546
547 GLubyte *srcMap, *dstMap;
548 GLint srcRowStride, dstRowStride;
549 GLuint i;
550
551
552 /* Determine datatype for resampling */
553 if (_mesa_get_format_max_bits(readFormat) == 8 &&
554 _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
555 pixelType = GL_UNSIGNED_BYTE;
556 pixelSize = 4 * sizeof(GLubyte);
557 }
558 else {
559 pixelType = GL_FLOAT;
560 pixelSize = 4 * sizeof(GLfloat);
561 }
562
563 /* Allocate the src/dst row buffers.
564 * Keep two adjacent src rows around for bilinear sampling.
565 */
566 srcBuffer0 = malloc(pixelSize * srcWidth);
567 srcBuffer1 = malloc(pixelSize * srcWidth);
568 dstBuffer = malloc(pixelSize * dstWidth);
569 if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
570 goto fail_no_memory;
571 }
572
573 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
574 gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
575 struct gl_renderbuffer_attachment *drawAtt;
576 struct gl_renderbuffer *drawRb;
577 mesa_format drawFormat;
578
579 if (idx == BUFFER_NONE)
580 continue;
581
582 drawAtt = &drawFb->Attachment[idx];
583 drawRb = drawAtt->Renderbuffer;
584 if (!drawRb)
585 continue;
586
587 drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
588
589 /*
590 * Map src / dst renderbuffers
591 */
592 if ((readRb == drawRb) ||
593 (readAtt->Texture && drawAtt->Texture &&
594 (readAtt->Texture == drawAtt->Texture))) {
595 /* map whole buffer for read/write */
596 ctx->Driver.MapRenderbuffer(ctx, readRb,
597 0, 0, readRb->Width, readRb->Height,
598 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
599 &srcMap, &srcRowStride,
600 readFb->FlipY);
601 if (!srcMap) {
602 goto fail_no_memory;
603 }
604
605 dstMap = srcMap;
606 dstRowStride = srcRowStride;
607 }
608 else {
609 /* different src/dst buffers */
610 /* XXX with a bit of work we could just map the regions to be
611 * read/written instead of the whole buffers.
612 */
613 ctx->Driver.MapRenderbuffer(ctx, readRb,
614 0, 0, readRb->Width, readRb->Height,
615 GL_MAP_READ_BIT, &srcMap, &srcRowStride,
616 readFb->FlipY);
617 if (!srcMap) {
618 goto fail_no_memory;
619 }
620 ctx->Driver.MapRenderbuffer(ctx, drawRb,
621 0, 0, drawRb->Width, drawRb->Height,
622 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
623 drawFb->FlipY);
624 if (!dstMap) {
625 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
626 goto fail_no_memory;
627 }
628 }
629
630 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
631 const GLint dstY = dstYpos + dstRow;
632 GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
633 GLint srcRow0 = MAX2(0, util_ifloor(srcRow));
634 GLint srcRow1 = srcRow0 + 1;
635 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
636
637 if (srcRow1 == srcHeight) {
638 /* last row fudge */
639 srcRow1 = srcRow0;
640 rowWeight = 0.0;
641 }
642
643 if (invertY) {
644 srcRow0 = srcHeight - 1 - srcRow0;
645 srcRow1 = srcHeight - 1 - srcRow1;
646 }
647
648 srcY0 = srcYpos + srcRow0;
649 srcY1 = srcYpos + srcRow1;
650
651 /* get the two source rows */
652 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
653 /* use same source row buffers again */
654 }
655 else if (srcY0 == srcBufferY1) {
656 /* move buffer1 into buffer0 by swapping pointers */
657 GLvoid *tmp = srcBuffer0;
658 srcBuffer0 = srcBuffer1;
659 srcBuffer1 = tmp;
660 /* get y1 row */
661 {
662 GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
663 if (pixelType == GL_UNSIGNED_BYTE) {
664 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
665 src, srcBuffer1);
666 }
667 else {
668 _mesa_unpack_rgba_row(readFormat, srcWidth,
669 src, srcBuffer1);
670 }
671 }
672 srcBufferY0 = srcY0;
673 srcBufferY1 = srcY1;
674 }
675 else {
676 /* get both new rows */
677 {
678 GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
679 GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
680 if (pixelType == GL_UNSIGNED_BYTE) {
681 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
682 src0, srcBuffer0);
683 _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
684 src1, srcBuffer1);
685 }
686 else {
687 _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
688 _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
689 }
690 }
691 srcBufferY0 = srcY0;
692 srcBufferY1 = srcY1;
693 }
694
695 if (pixelType == GL_UNSIGNED_BYTE) {
696 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
697 dstBuffer, invertX, rowWeight);
698 }
699 else {
700 resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
701 dstBuffer, invertX, rowWeight);
702 }
703
704 /* store pixel row in destination */
705 {
706 GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
707 if (pixelType == GL_UNSIGNED_BYTE) {
708 _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
709 }
710 else {
711 _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
712 }
713 }
714 }
715
716 ctx->Driver.UnmapRenderbuffer(ctx, readRb);
717 if (drawRb != readRb) {
718 ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
719 }
720 }
721
722 free(srcBuffer0);
723 free(srcBuffer1);
724 free(dstBuffer);
725 return;
726
727 fail_no_memory:
728 free(srcBuffer0);
729 free(srcBuffer1);
730 free(dstBuffer);
731 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
732 }
733
734
735
736 /**
737 * Software fallback for glBlitFramebufferEXT().
738 */
739 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)740 _swrast_BlitFramebuffer(struct gl_context *ctx,
741 struct gl_framebuffer *readFb,
742 struct gl_framebuffer *drawFb,
743 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
744 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
745 GLbitfield mask, GLenum filter)
746 {
747 static const GLbitfield buffers[3] = {
748 GL_COLOR_BUFFER_BIT,
749 GL_DEPTH_BUFFER_BIT,
750 GL_STENCIL_BUFFER_BIT
751 };
752 static const GLenum buffer_enums[3] = {
753 GL_COLOR,
754 GL_DEPTH,
755 GL_STENCIL,
756 };
757 GLint i;
758
759 /* Page 679 of OpenGL 4.4 spec says:
760 * "Added BlitFramebuffer to commands affected by conditional rendering in
761 * section 10.10 (Bug 9562)."
762 */
763 if (!_mesa_check_conditional_render(ctx))
764 return; /* Do not blit */
765
766 if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1,
767 &dstX0, &dstY0, &dstX1, &dstY1)) {
768 return;
769 }
770
771 if (SWRAST_CONTEXT(ctx)->NewState)
772 _swrast_validate_derived(ctx);
773
774 /* First, try covering whatever buffers possible using the fast 1:1 copy
775 * path.
776 */
777 if (srcX1 - srcX0 == dstX1 - dstX0 &&
778 srcY1 - srcY0 == dstY1 - dstY0 &&
779 srcX0 < srcX1 &&
780 srcY0 < srcY1 &&
781 dstX0 < dstX1 &&
782 dstY0 < dstY1) {
783 for (i = 0; i < 3; i++) {
784 if (mask & buffers[i]) {
785 if (swrast_fast_copy_pixels(ctx,
786 readFb, drawFb,
787 srcX0, srcY0,
788 srcX1 - srcX0, srcY1 - srcY0,
789 dstX0, dstY0,
790 buffer_enums[i])) {
791 mask &= ~buffers[i];
792 }
793 }
794 }
795
796 if (!mask)
797 return;
798 }
799
800 if (filter == GL_NEAREST) {
801 for (i = 0; i < 3; i++) {
802 if (mask & buffers[i]) {
803 blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
804 dstX0, dstY0, dstX1, dstY1, buffers[i]);
805 }
806 }
807 }
808 else {
809 assert(filter == GL_LINEAR);
810 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */
811 blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
812 dstX0, dstY0, dstX1, dstY1);
813 }
814 }
815
816 }
817