Merge commit 'origin/gallium-0.1'
[mesa.git] / src / mesa / swrast / s_blit.c
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/macros.h"
28 #include "s_context.h"
29
30
31 #define ABS(X) ((X) < 0 ? -(X) : (X))
32
33
34 /**
35 * Generate a row resampler function for GL_NEAREST mode.
36 */
37 #define RESAMPLE(NAME, PIXELTYPE, SIZE) \
38 static void \
39 NAME(GLint srcWidth, GLint dstWidth, \
40 const GLvoid *srcBuffer, GLvoid *dstBuffer, \
41 GLboolean flip) \
42 { \
43 const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
44 PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \
45 GLint dstCol; \
46 \
47 if (flip) { \
48 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
49 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
50 ASSERT(srcCol >= 0); \
51 ASSERT(srcCol < srcWidth); \
52 srcCol = srcWidth - 1 - srcCol; /* flip */ \
53 if (SIZE == 1) { \
54 dst[dstCol] = src[srcCol]; \
55 } \
56 else if (SIZE == 2) { \
57 dst[dstCol*2+0] = src[srcCol*2+0]; \
58 dst[dstCol*2+1] = src[srcCol*2+1]; \
59 } \
60 else if (SIZE == 4) { \
61 dst[dstCol*4+0] = src[srcCol*4+0]; \
62 dst[dstCol*4+1] = src[srcCol*4+1]; \
63 dst[dstCol*4+2] = src[srcCol*4+2]; \
64 dst[dstCol*4+3] = src[srcCol*4+3]; \
65 } \
66 } \
67 } \
68 else { \
69 for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
70 GLint srcCol = (dstCol * srcWidth) / dstWidth; \
71 ASSERT(srcCol >= 0); \
72 ASSERT(srcCol < srcWidth); \
73 if (SIZE == 1) { \
74 dst[dstCol] = src[srcCol]; \
75 } \
76 else if (SIZE == 2) { \
77 dst[dstCol*2+0] = src[srcCol*2+0]; \
78 dst[dstCol*2+1] = src[srcCol*2+1]; \
79 } \
80 else if (SIZE == 4) { \
81 dst[dstCol*4+0] = src[srcCol*4+0]; \
82 dst[dstCol*4+1] = src[srcCol*4+1]; \
83 dst[dstCol*4+2] = src[srcCol*4+2]; \
84 dst[dstCol*4+3] = src[srcCol*4+3]; \
85 } \
86 } \
87 } \
88 }
89
90 /**
91 * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
92 */
93 RESAMPLE(resample_row_1, GLubyte, 1)
94 RESAMPLE(resample_row_2, GLushort, 1)
95 RESAMPLE(resample_row_4, GLuint, 1)
96 RESAMPLE(resample_row_8, GLuint, 2)
97 RESAMPLE(resample_row_16, GLuint, 4)
98
99
100 /**
101 * Blit color, depth or stencil with GL_NEAREST filtering.
102 */
103 static void
104 blit_nearest(GLcontext *ctx,
105 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
106 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
107 GLenum buffer)
108 {
109 struct gl_renderbuffer *readRb, *drawRb;
110
111 const GLint srcWidth = ABS(srcX1 - srcX0);
112 const GLint dstWidth = ABS(dstX1 - dstX0);
113 const GLint srcHeight = ABS(srcY1 - srcY0);
114 const GLint dstHeight = ABS(dstY1 - dstY0);
115
116 const GLint srcXpos = MIN2(srcX0, srcX1);
117 const GLint srcYpos = MIN2(srcY0, srcY1);
118 const GLint dstXpos = MIN2(dstX0, dstX1);
119 const GLint dstYpos = MIN2(dstY0, dstY1);
120
121 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
122 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
123
124 GLint dstRow;
125
126 GLint comps, pixelSize;
127 GLvoid *srcBuffer, *dstBuffer;
128 GLint prevY = -1;
129
130 typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
131 const GLvoid *srcBuffer, GLvoid *dstBuffer,
132 GLboolean flip);
133 resample_func resampleRow;
134
135 switch (buffer) {
136 case GL_COLOR_BUFFER_BIT:
137 readRb = ctx->ReadBuffer->_ColorReadBuffer;
138 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
139 comps = 4;
140 break;
141 case GL_DEPTH_BUFFER_BIT:
142 readRb = ctx->ReadBuffer->_DepthBuffer;
143 drawRb = ctx->DrawBuffer->_DepthBuffer;
144 comps = 1;
145 break;
146 case GL_STENCIL_BUFFER_BIT:
147 readRb = ctx->ReadBuffer->_StencilBuffer;
148 drawRb = ctx->DrawBuffer->_StencilBuffer;
149 comps = 1;
150 break;
151 default:
152 _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
153 return;
154 }
155
156 switch (readRb->DataType) {
157 case GL_UNSIGNED_BYTE:
158 pixelSize = comps * sizeof(GLubyte);
159 break;
160 case GL_UNSIGNED_SHORT:
161 pixelSize = comps * sizeof(GLushort);
162 break;
163 case GL_UNSIGNED_INT:
164 pixelSize = comps * sizeof(GLuint);
165 break;
166 case GL_FLOAT:
167 pixelSize = comps * sizeof(GLfloat);
168 break;
169 default:
170 _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest",
171 readRb->DataType);
172 return;
173 }
174
175 /* choose row resampler */
176 switch (pixelSize) {
177 case 1:
178 resampleRow = resample_row_1;
179 break;
180 case 2:
181 resampleRow = resample_row_2;
182 break;
183 case 4:
184 resampleRow = resample_row_4;
185 break;
186 case 8:
187 resampleRow = resample_row_8;
188 break;
189 case 16:
190 resampleRow = resample_row_16;
191 break;
192 default:
193 _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
194 pixelSize);
195 return;
196 }
197
198 /* allocate the src/dst row buffers */
199 srcBuffer = _mesa_malloc(pixelSize * srcWidth);
200 if (!srcBuffer) {
201 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
202 return;
203 }
204 dstBuffer = _mesa_malloc(pixelSize * dstWidth);
205 if (!dstBuffer) {
206 _mesa_free(srcBuffer);
207 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
208 return;
209 }
210
211 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
212 const GLint dstY = dstYpos + dstRow;
213 GLint srcRow = (dstRow * srcHeight) / dstHeight;
214 GLint srcY;
215
216 ASSERT(srcRow >= 0);
217 ASSERT(srcRow < srcHeight);
218
219 if (invertY) {
220 srcRow = srcHeight - 1 - srcRow;
221 }
222
223 srcY = srcYpos + srcRow;
224
225 /* get pixel row from source and resample to match dest width */
226 if (prevY != srcY) {
227 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY, srcBuffer);
228 (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
229 prevY = srcY;
230 }
231
232 /* store pixel row in destination */
233 drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL);
234 }
235
236 _mesa_free(srcBuffer);
237 _mesa_free(dstBuffer);
238 }
239
240
241
242 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
243
244 static INLINE GLfloat
245 lerp_2d(GLfloat a, GLfloat b,
246 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
247 {
248 const GLfloat temp0 = LERP(a, v00, v10);
249 const GLfloat temp1 = LERP(a, v01, v11);
250 return LERP(b, temp0, temp1);
251 }
252
253
254 /**
255 * Bilinear interpolation of two source rows.
256 * GLubyte pixels.
257 */
258 static void
259 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
260 const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
261 GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
262 {
263 const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
264 const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
265 GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
266 const GLfloat dstWidthF = (GLfloat) dstWidth;
267 GLint dstCol;
268
269 for (dstCol = 0; dstCol < dstWidth; dstCol++) {
270 const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF;
271 GLint srcCol0 = IFLOOR(srcCol);
272 GLint srcCol1 = srcCol0 + 1;
273 GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
274 GLfloat red, green, blue, alpha;
275
276 ASSERT(srcCol0 >= 0);
277 ASSERT(srcCol0 < srcWidth);
278 ASSERT(srcCol1 <= srcWidth);
279
280 if (srcCol1 == srcWidth) {
281 /* last column fudge */
282 srcCol1--;
283 colWeight = 0.0;
284 }
285
286 if (flip) {
287 srcCol0 = srcWidth - 1 - srcCol0;
288 srcCol1 = srcWidth - 1 - srcCol1;
289 }
290
291 red = lerp_2d(colWeight, rowWeight,
292 srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
293 srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
294 green = lerp_2d(colWeight, rowWeight,
295 srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
296 srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
297 blue = lerp_2d(colWeight, rowWeight,
298 srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
299 srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
300 alpha = lerp_2d(colWeight, rowWeight,
301 srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
302 srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
303
304 dstColor[dstCol][RCOMP] = IFLOOR(red);
305 dstColor[dstCol][GCOMP] = IFLOOR(green);
306 dstColor[dstCol][BCOMP] = IFLOOR(blue);
307 dstColor[dstCol][ACOMP] = IFLOOR(alpha);
308 }
309 }
310
311
312
313 /**
314 * Bilinear filtered blit (color only).
315 */
316 static void
317 blit_linear(GLcontext *ctx,
318 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
319 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
320 {
321 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
322 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
323
324 const GLint srcWidth = ABS(srcX1 - srcX0);
325 const GLint dstWidth = ABS(dstX1 - dstX0);
326 const GLint srcHeight = ABS(srcY1 - srcY0);
327 const GLint dstHeight = ABS(dstY1 - dstY0);
328 const GLfloat dstHeightF = (GLfloat) dstHeight;
329
330 const GLint srcXpos = MIN2(srcX0, srcX1);
331 const GLint srcYpos = MIN2(srcY0, srcY1);
332 const GLint dstXpos = MIN2(dstX0, dstX1);
333 const GLint dstYpos = MIN2(dstY0, dstY1);
334
335 const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
336 const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
337
338 GLint dstRow;
339
340 GLint pixelSize;
341 GLvoid *srcBuffer0, *srcBuffer1;
342 GLint srcBufferY0 = -1, srcBufferY1 = -1;
343 GLvoid *dstBuffer;
344
345 switch (readRb->DataType) {
346 case GL_UNSIGNED_BYTE:
347 pixelSize = 4 * sizeof(GLubyte);
348 break;
349 case GL_UNSIGNED_SHORT:
350 pixelSize = 4 * sizeof(GLushort);
351 break;
352 case GL_UNSIGNED_INT:
353 pixelSize = 4 * sizeof(GLuint);
354 break;
355 case GL_FLOAT:
356 pixelSize = 4 * sizeof(GLfloat);
357 break;
358 default:
359 _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest",
360 readRb->DataType);
361 return;
362 }
363
364 /* Allocate the src/dst row buffers.
365 * Keep two adjacent src rows around for bilinear sampling.
366 */
367 srcBuffer0 = _mesa_malloc(pixelSize * srcWidth);
368 if (!srcBuffer0) {
369 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
370 return;
371 }
372 srcBuffer1 = _mesa_malloc(pixelSize * srcWidth);
373 if (!srcBuffer1) {
374 _mesa_free(srcBuffer0);
375 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
376 return;
377 }
378 dstBuffer = _mesa_malloc(pixelSize * dstWidth);
379 if (!dstBuffer) {
380 _mesa_free(srcBuffer0);
381 _mesa_free(srcBuffer1);
382 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
383 return;
384 }
385
386 for (dstRow = 0; dstRow < dstHeight; dstRow++) {
387 const GLint dstY = dstYpos + dstRow;
388 const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
389 GLint srcRow0 = IFLOOR(srcRow);
390 GLint srcRow1 = srcRow0 + 1;
391 GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
392
393 ASSERT(srcRow >= 0);
394 ASSERT(srcRow < srcHeight);
395
396 if (srcRow1 == srcHeight) {
397 /* last row fudge */
398 srcRow1 = srcRow0;
399 rowWeight = 0.0;
400 }
401
402 if (invertY) {
403 srcRow0 = srcHeight - 1 - srcRow0;
404 srcRow1 = srcHeight - 1 - srcRow1;
405 }
406
407 srcY0 = srcYpos + srcRow0;
408 srcY1 = srcYpos + srcRow1;
409
410 /* get the two source rows */
411 if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
412 /* use same source row buffers again */
413 }
414 else if (srcY0 == srcBufferY1) {
415 /* move buffer1 into buffer0 by swapping pointers */
416 GLvoid *tmp = srcBuffer0;
417 srcBuffer0 = srcBuffer1;
418 srcBuffer1 = tmp;
419 /* get y1 row */
420 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1);
421 srcBufferY0 = srcY0;
422 srcBufferY1 = srcY1;
423 }
424 else {
425 /* get both new rows */
426 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY0, srcBuffer0);
427 readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1);
428 srcBufferY0 = srcY0;
429 srcBufferY1 = srcY1;
430 }
431
432 if (readRb->DataType == GL_UNSIGNED_BYTE) {
433 resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
434 dstBuffer, invertX, rowWeight);
435 }
436 else {
437 _mesa_problem(ctx, "Unsupported color channel type in sw blit");
438 break;
439 }
440
441 /* store pixel row in destination */
442 drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL);
443 }
444
445 _mesa_free(srcBuffer0);
446 _mesa_free(srcBuffer1);
447 _mesa_free(dstBuffer);
448 }
449
450
451 /**
452 * Simple case: Blit color, depth or stencil with no scaling or flipping.
453 * XXX we could easily support vertical flipping here.
454 */
455 static void
456 simple_blit(GLcontext *ctx,
457 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
458 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
459 GLenum buffer)
460 {
461 struct gl_renderbuffer *readRb, *drawRb;
462 const GLint width = srcX1 - srcX0;
463 const GLint height = srcY1 - srcY0;
464 GLint row, srcY, dstY, yStep;
465 GLint comps, bytesPerRow;
466 void *rowBuffer;
467
468 /* only one buffer */
469 ASSERT(_mesa_bitcount(buffer) == 1);
470 /* no flipping checks */
471 ASSERT(srcX0 < srcX1);
472 ASSERT(srcY0 < srcY1);
473 ASSERT(dstX0 < dstX1);
474 ASSERT(dstY0 < dstY1);
475 /* size checks */
476 ASSERT(srcX1 - srcX0 == dstX1 - dstX0);
477 ASSERT(srcY1 - srcY0 == dstY1 - dstY0);
478
479 /* determine if copy should be bottom-to-top or top-to-bottom */
480 if (srcY0 > dstY0) {
481 /* src above dst: copy bottom-to-top */
482 yStep = 1;
483 srcY = srcY0;
484 dstY = dstY0;
485 }
486 else {
487 /* src below dst: copy top-to-bottom */
488 yStep = -1;
489 srcY = srcY1 - 1;
490 dstY = dstY1 - 1;
491 }
492
493 switch (buffer) {
494 case GL_COLOR_BUFFER_BIT:
495 readRb = ctx->ReadBuffer->_ColorReadBuffer;
496 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
497 comps = 4;
498 break;
499 case GL_DEPTH_BUFFER_BIT:
500 readRb = ctx->ReadBuffer->_DepthBuffer;
501 drawRb = ctx->DrawBuffer->_DepthBuffer;
502 comps = 1;
503 break;
504 case GL_STENCIL_BUFFER_BIT:
505 readRb = ctx->ReadBuffer->_StencilBuffer;
506 drawRb = ctx->DrawBuffer->_StencilBuffer;
507 comps = 1;
508 break;
509 default:
510 _mesa_problem(ctx, "unexpected buffer in simple_blit()");
511 return;
512 }
513
514 ASSERT(readRb->DataType == drawRb->DataType);
515
516 /* compute bytes per row */
517 switch (readRb->DataType) {
518 case GL_UNSIGNED_BYTE:
519 bytesPerRow = comps * width * sizeof(GLubyte);
520 break;
521 case GL_UNSIGNED_SHORT:
522 bytesPerRow = comps * width * sizeof(GLushort);
523 break;
524 case GL_UNSIGNED_INT:
525 bytesPerRow = comps * width * sizeof(GLuint);
526 break;
527 case GL_FLOAT:
528 bytesPerRow = comps * width * sizeof(GLfloat);
529 break;
530 default:
531 _mesa_problem(ctx, "unexpected buffer type in simple_blit");
532 return;
533 }
534
535 /* allocate the row buffer */
536 rowBuffer = _mesa_malloc(bytesPerRow);
537 if (!rowBuffer) {
538 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
539 return;
540 }
541
542 for (row = 0; row < height; row++) {
543 readRb->GetRow(ctx, readRb, width, srcX0, srcY, rowBuffer);
544 drawRb->PutRow(ctx, drawRb, width, dstX0, dstY, rowBuffer, NULL);
545 srcY += yStep;
546 dstY += yStep;
547 }
548
549 _mesa_free(rowBuffer);
550 }
551
552
553 /**
554 * Clip dst coords against Xmax (or Ymax).
555 */
556 static INLINE void
557 clip_right_or_top(GLint *srcX0, GLint *srcX1,
558 GLint *dstX0, GLint *dstX1,
559 GLint maxValue)
560 {
561 GLfloat t, bias;
562
563 if (*dstX1 > maxValue) {
564 /* X1 outside right edge */
565 ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */
566 t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
567 /* chop off [t, 1] part */
568 ASSERT(t >= 0.0 && t <= 1.0);
569 *dstX1 = maxValue;
570 bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
571 *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
572 }
573 else if (*dstX0 > maxValue) {
574 /* X0 outside right edge */
575 ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */
576 t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
577 /* chop off [t, 1] part */
578 ASSERT(t >= 0.0 && t <= 1.0);
579 *dstX0 = maxValue;
580 bias = (*srcX0 < *srcX1) ? -0.5 : 0.5;
581 *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
582 }
583 }
584
585
586 /**
587 * Clip dst coords against Xmin (or Ymin).
588 */
589 static INLINE void
590 clip_left_or_bottom(GLint *srcX0, GLint *srcX1,
591 GLint *dstX0, GLint *dstX1,
592 GLint minValue)
593 {
594 GLfloat t, bias;
595
596 if (*dstX0 < minValue) {
597 /* X0 outside left edge */
598 ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */
599 t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
600 /* chop off [0, t] part */
601 ASSERT(t >= 0.0 && t <= 1.0);
602 *dstX0 = minValue;
603 bias = (*srcX0 < *srcX1) ? 0.5 : -0.5; /* flipped??? */
604 *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
605 }
606 else if (*dstX1 < minValue) {
607 /* X1 outside left edge */
608 ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */
609 t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
610 /* chop off [0, t] part */
611 ASSERT(t >= 0.0 && t <= 1.0);
612 *dstX1 = minValue;
613 bias = (*srcX0 < *srcX1) ? 0.5 : -0.5;
614 *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
615 }
616 }
617
618
619 /**
620 * Do clipping of blit src/dest rectangles.
621 * The dest rect is clipped against both the buffer bounds and scissor bounds.
622 * The src rect is just clipped against the buffer bounds.
623 *
624 * When either the src or dest rect is clipped, the other is also clipped
625 * proportionately!
626 *
627 * Note that X0 need not be less than X1 (same for Y) for either the source
628 * and dest rects. That makes the clipping a little trickier.
629 *
630 * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
631 */
632 static GLboolean
633 clip_blit(GLcontext *ctx,
634 GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
635 GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
636 {
637 const GLint srcXmin = 0;
638 const GLint srcXmax = ctx->ReadBuffer->Width;
639 const GLint srcYmin = 0;
640 const GLint srcYmax = ctx->ReadBuffer->Height;
641
642 /* these include scissor bounds */
643 const GLint dstXmin = ctx->DrawBuffer->_Xmin;
644 const GLint dstXmax = ctx->DrawBuffer->_Xmax;
645 const GLint dstYmin = ctx->DrawBuffer->_Ymin;
646 const GLint dstYmax = ctx->DrawBuffer->_Ymax;
647
648 /*
649 printf("PreClipX: src: %d .. %d dst: %d .. %d\n",
650 *srcX0, *srcX1, *dstX0, *dstX1);
651 printf("PreClipY: src: %d .. %d dst: %d .. %d\n",
652 *srcY0, *srcY1, *dstY0, *dstY1);
653 */
654
655 /* trivial rejection tests */
656 if (*dstX0 == *dstX1)
657 return GL_FALSE; /* no width */
658 if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
659 return GL_FALSE; /* totally out (left) of bounds */
660 if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
661 return GL_FALSE; /* totally out (right) of bounds */
662
663 if (*dstY0 == *dstY1)
664 return GL_FALSE;
665 if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
666 return GL_FALSE;
667 if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
668 return GL_FALSE;
669
670 if (*srcX0 == *srcX1)
671 return GL_FALSE;
672 if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
673 return GL_FALSE;
674 if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
675 return GL_FALSE;
676
677 if (*srcY0 == *srcY1)
678 return GL_FALSE;
679 if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
680 return GL_FALSE;
681 if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
682 return GL_FALSE;
683
684 /*
685 * dest clip
686 */
687 clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
688 clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
689 clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
690 clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
691
692 /*
693 * src clip (just swap src/dst values from above)
694 */
695 clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
696 clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
697 clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
698 clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
699
700 /*
701 printf("PostClipX: src: %d .. %d dst: %d .. %d\n",
702 *srcX0, *srcX1, *dstX0, *dstX1);
703 printf("PostClipY: src: %d .. %d dst: %d .. %d\n",
704 *srcY0, *srcY1, *dstY0, *dstY1);
705 */
706
707 ASSERT(*dstX0 >= dstXmin);
708 ASSERT(*dstX0 <= dstXmax);
709 ASSERT(*dstX1 >= dstXmin);
710 ASSERT(*dstX1 <= dstXmax);
711
712 ASSERT(*dstY0 >= dstYmin);
713 ASSERT(*dstY0 <= dstYmax);
714 ASSERT(*dstY1 >= dstYmin);
715 ASSERT(*dstY1 <= dstYmax);
716
717 ASSERT(*srcX0 >= srcXmin);
718 ASSERT(*srcX0 <= srcXmax);
719 ASSERT(*srcX1 >= srcXmin);
720 ASSERT(*srcX1 <= srcXmax);
721
722 ASSERT(*srcY0 >= srcYmin);
723 ASSERT(*srcY0 <= srcYmax);
724 ASSERT(*srcY1 >= srcYmin);
725 ASSERT(*srcY1 <= srcYmax);
726
727 return GL_TRUE;
728 }
729
730
731 /**
732 * Software fallback for glBlitFramebufferEXT().
733 */
734 void
735 _swrast_BlitFramebuffer(GLcontext *ctx,
736 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
737 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
738 GLbitfield mask, GLenum filter)
739 {
740 static const GLint buffers[3] = {
741 GL_COLOR_BUFFER_BIT,
742 GL_DEPTH_BUFFER_BIT,
743 GL_STENCIL_BUFFER_BIT
744 };
745 GLint i;
746
747 if (!ctx->DrawBuffer->_NumColorDrawBuffers)
748 return;
749
750 if (!clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
751 &dstX0, &dstY0, &dstX1, &dstY1)) {
752 return;
753 }
754
755 swrast_render_start(ctx);
756
757 if (srcX1 - srcX0 == dstX1 - dstX0 &&
758 srcY1 - srcY0 == dstY1 - dstY0 &&
759 srcX0 < srcX1 &&
760 srcY0 < srcY1 &&
761 dstX0 < dstX1 &&
762 dstY0 < dstY1) {
763 /* no stretching or flipping.
764 * filter doesn't matter.
765 */
766 for (i = 0; i < 3; i++) {
767 if (mask & buffers[i]) {
768 simple_blit(ctx, srcX0, srcY0, srcX1, srcY1,
769 dstX0, dstY0, dstX1, dstY1, buffers[i]);
770 }
771 }
772 }
773 else {
774 if (filter == GL_NEAREST) {
775 for (i = 0; i < 3; i++) {
776 if (mask & buffers[i]) {
777 blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1,
778 dstX0, dstY0, dstX1, dstY1, buffers[i]);
779 }
780 }
781 }
782 else {
783 ASSERT(filter == GL_LINEAR);
784 if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */
785 blit_linear(ctx, srcX0, srcY0, srcX1, srcY1,
786 dstX0, dstY0, dstX1, dstY1);
787 }
788 }
789 }
790
791 swrast_render_finish(ctx);
792 }