~gma500/+junk/gma500-maverick

« back to all changes in this revision

Viewing changes to xpsb-glx/mesa/src/mesa/swrast/s_blit.c

  • Committer: Luca Forina
  • Date: 2011-02-14 09:55:00 UTC
  • Revision ID: luca.forina@gmail.com-20110214095500-kq7o333fbjuoquqs
new commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
741
   static const GLint buffers[3] = {
 
742
      GL_COLOR_BUFFER_BIT,
 
743
      GL_DEPTH_BUFFER_BIT,
 
744
      GL_STENCIL_BUFFER_BIT
 
745
   };
 
746
   GLint i;
 
747
 
 
748
   if (!ctx->DrawBuffer->_NumColorDrawBuffers)
 
749
      return;
 
750
 
 
751
   if (!clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
 
752
                  &dstX0, &dstY0, &dstX1, &dstY1)) {
 
753
      return;
 
754
   }
 
755
 
 
756
   RENDER_START(swrast, ctx);
 
757
 
 
758
   if (srcX1 - srcX0 == dstX1 - dstX0 &&
 
759
       srcY1 - srcY0 == dstY1 - dstY0 &&
 
760
       srcX0 < srcX1 &&
 
761
       srcY0 < srcY1 &&
 
762
       dstX0 < dstX1 &&
 
763
       dstY0 < dstY1) {
 
764
      /* no stretching or flipping.
 
765
       * filter doesn't matter.
 
766
       */
 
767
      for (i = 0; i < 3; i++) {
 
768
         if (mask & buffers[i]) {
 
769
            simple_blit(ctx, srcX0, srcY0, srcX1, srcY1,
 
770
                        dstX0, dstY0, dstX1, dstY1, buffers[i]);
 
771
         }
 
772
      }
 
773
   }
 
774
   else {
 
775
      if (filter == GL_NEAREST) {
 
776
         for (i = 0; i < 3; i++) {
 
777
            if (mask & buffers[i]) {
 
778
               blit_nearest(ctx,  srcX0, srcY0, srcX1, srcY1,
 
779
                            dstX0, dstY0, dstX1, dstY1, buffers[i]);
 
780
            }
 
781
         }
 
782
      }
 
783
      else {
 
784
         ASSERT(filter == GL_LINEAR);
 
785
         if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
 
786
            blit_linear(ctx,  srcX0, srcY0, srcX1, srcY1,
 
787
                        dstX0, dstY0, dstX1, dstY1);
 
788
         }
 
789
      }
 
790
   }
 
791
 
 
792
   RENDER_FINISH(swrast, ctx);
 
793
}