Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5563 serge 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 "s_context.h"
33
 
34
 
35
#define ABS(X)   ((X) < 0 ? -(X) : (X))
36
 
37
 
38
/**
39
 * Generate a row resampler function for GL_NEAREST mode.
40
 */
41
#define RESAMPLE(NAME, PIXELTYPE, SIZE)			\
42
static void						\
43
NAME(GLint srcWidth, GLint dstWidth,			\
44
     const GLvoid *srcBuffer, GLvoid *dstBuffer,	\
45
     GLboolean flip)					\
46
{							\
47
   const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
48
   PIXELTYPE *dst = (PIXELTYPE *) dstBuffer;		\
49
   GLint dstCol;					\
50
							\
51
   if (flip) {						\
52
      for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
53
         GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
54
         ASSERT(srcCol >= 0);				\
55
         ASSERT(srcCol < srcWidth);			\
56
         srcCol = srcWidth - 1 - srcCol; /* flip */	\
57
         if (SIZE == 1) {				\
58
            dst[dstCol] = src[srcCol];			\
59
         }						\
60
         else if (SIZE == 2) {				\
61
            dst[dstCol*2+0] = src[srcCol*2+0];		\
62
            dst[dstCol*2+1] = src[srcCol*2+1];		\
63
         }						\
64
         else if (SIZE == 4) {				\
65
            dst[dstCol*4+0] = src[srcCol*4+0];		\
66
            dst[dstCol*4+1] = src[srcCol*4+1];		\
67
            dst[dstCol*4+2] = src[srcCol*4+2];		\
68
            dst[dstCol*4+3] = src[srcCol*4+3];		\
69
         }						\
70
      }							\
71
   }							\
72
   else {						\
73
      for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
74
         GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
75
         ASSERT(srcCol >= 0);				\
76
         ASSERT(srcCol < srcWidth);			\
77
         if (SIZE == 1) {				\
78
            dst[dstCol] = src[srcCol];			\
79
         }						\
80
         else if (SIZE == 2) {				\
81
            dst[dstCol*2+0] = src[srcCol*2+0];		\
82
            dst[dstCol*2+1] = src[srcCol*2+1];		\
83
         }						\
84
         else if (SIZE == 4) {				\
85
            dst[dstCol*4+0] = src[srcCol*4+0];		\
86
            dst[dstCol*4+1] = src[srcCol*4+1];		\
87
            dst[dstCol*4+2] = src[srcCol*4+2];		\
88
            dst[dstCol*4+3] = src[srcCol*4+3];		\
89
         }						\
90
      }							\
91
   }							\
92
}
93
 
94
/**
95
 * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
96
 */
97
RESAMPLE(resample_row_1, GLubyte, 1)
98
RESAMPLE(resample_row_2, GLushort, 1)
99
RESAMPLE(resample_row_4, GLuint, 1)
100
RESAMPLE(resample_row_8, GLuint, 2)
101
RESAMPLE(resample_row_16, GLuint, 4)
102
 
103
 
104
/**
105
 * Blit color, depth or stencil with GL_NEAREST filtering.
106
 */
107
static void
108
blit_nearest(struct gl_context *ctx,
109
             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
110
             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
111
             GLbitfield buffer)
112
{
113
   struct gl_renderbuffer *readRb, *drawRb = NULL;
114
   struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL;
115
   struct gl_framebuffer *readFb = ctx->ReadBuffer;
116
   struct gl_framebuffer *drawFb = ctx->DrawBuffer;
117
   GLuint numDrawBuffers = 0;
118
   GLuint i;
119
 
120
   const GLint srcWidth = ABS(srcX1 - srcX0);
121
   const GLint dstWidth = ABS(dstX1 - dstX0);
122
   const GLint srcHeight = ABS(srcY1 - srcY0);
123
   const GLint dstHeight = ABS(dstY1 - dstY0);
124
 
125
   const GLint srcXpos = MIN2(srcX0, srcX1);
126
   const GLint srcYpos = MIN2(srcY0, srcY1);
127
   const GLint dstXpos = MIN2(dstX0, dstX1);
128
   const GLint dstYpos = MIN2(dstY0, dstY1);
129
 
130
   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
131
   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
132
   enum mode {
133
      DIRECT,
134
      UNPACK_RGBA_FLOAT,
135
      UNPACK_Z_FLOAT,
136
      UNPACK_Z_INT,
137
      UNPACK_S,
138
   } mode = DIRECT;
139
   GLubyte *srcMap, *dstMap;
140
   GLint srcRowStride, dstRowStride;
141
   GLint dstRow;
142
 
143
   GLint pixelSize = 0;
144
   GLvoid *srcBuffer, *dstBuffer;
145
   GLint prevY = -1;
146
 
147
   typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
148
                                 const GLvoid *srcBuffer, GLvoid *dstBuffer,
149
                                 GLboolean flip);
150
   resample_func resampleRow;
151
 
152
   switch (buffer) {
153
   case GL_COLOR_BUFFER_BIT:
154
      readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
155
      readRb = readFb->_ColorReadBuffer;
156
      numDrawBuffers = drawFb->_NumColorDrawBuffers;
157
      break;
158
   case GL_DEPTH_BUFFER_BIT:
159
      readAtt = &readFb->Attachment[BUFFER_DEPTH];
160
      drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
161
      readRb = readAtt->Renderbuffer;
162
      drawRb = drawAtt->Renderbuffer;
163
      numDrawBuffers = 1;
164
 
165
      /* Note that for depth/stencil, the formats of src/dst must match.  By
166
       * using the core helpers for pack/unpack, we avoid needing to handle
167
       * masking for things like DEPTH copies of Z24S8.
168
       */
169
      if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
170
	  readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
171
	 mode = UNPACK_Z_FLOAT;
172
      } else {
173
	 mode = UNPACK_Z_INT;
174
      }
175
      pixelSize = 4;
176
      break;
177
   case GL_STENCIL_BUFFER_BIT:
178
      readAtt = &readFb->Attachment[BUFFER_STENCIL];
179
      drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
180
      readRb = readAtt->Renderbuffer;
181
      drawRb = drawAtt->Renderbuffer;
182
      numDrawBuffers = 1;
183
      mode = UNPACK_S;
184
      pixelSize = 1;
185
      break;
186
   default:
187
      _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
188
      return;
189
   }
190
 
191
   /* allocate the src/dst row buffers */
192
   srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth);
193
   dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth);
194
   if (!srcBuffer || !dstBuffer)
195
      goto fail_no_memory;
196
 
197
   /* Blit to all the draw buffers */
198
   for (i = 0; i < numDrawBuffers; i++) {
199
      if (buffer == GL_COLOR_BUFFER_BIT) {
200
         int idx = drawFb->_ColorDrawBufferIndexes[i];
201
         if (idx == -1)
202
            continue;
203
         drawAtt = &drawFb->Attachment[idx];
204
         drawRb = drawAtt->Renderbuffer;
205
 
206
         if (!drawRb)
207
            continue;
208
 
209
         if (readRb->Format == drawRb->Format) {
210
            mode = DIRECT;
211
            pixelSize = _mesa_get_format_bytes(readRb->Format);
212
         } else {
213
            mode = UNPACK_RGBA_FLOAT;
214
            pixelSize = 16;
215
         }
216
      }
217
 
218
      /* choose row resampler */
219
      switch (pixelSize) {
220
      case 1:
221
         resampleRow = resample_row_1;
222
         break;
223
      case 2:
224
         resampleRow = resample_row_2;
225
         break;
226
      case 4:
227
         resampleRow = resample_row_4;
228
         break;
229
      case 8:
230
         resampleRow = resample_row_8;
231
         break;
232
      case 16:
233
         resampleRow = resample_row_16;
234
         break;
235
      default:
236
         _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
237
                       pixelSize);
238
         goto fail;
239
      }
240
 
241
      if ((readRb == drawRb) ||
242
          (readAtt->Texture && drawAtt->Texture &&
243
           (readAtt->Texture == drawAtt->Texture))) {
244
         /* map whole buffer for read/write */
245
         /* XXX we could be clever and just map the union region of the
246
          * source and dest rects.
247
          */
248
         GLubyte *map;
249
         GLint rowStride;
250
         GLint formatSize = _mesa_get_format_bytes(readRb->Format);
251
 
252
         ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
253
                                     readRb->Width, readRb->Height,
254
                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
255
                                     &map, &rowStride);
256
         if (!map) {
257
            goto fail_no_memory;
258
         }
259
 
260
         srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
261
         dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
262
 
263
         /* this handles overlapping copies */
264
         if (srcY0 < dstY0) {
265
            /* copy in reverse (top->down) order */
266
            srcMap += rowStride * (readRb->Height - 1);
267
            dstMap += rowStride * (readRb->Height - 1);
268
            srcRowStride = -rowStride;
269
            dstRowStride = -rowStride;
270
         }
271
         else {
272
            /* copy in normal (bottom->up) order */
273
            srcRowStride = rowStride;
274
            dstRowStride = rowStride;
275
         }
276
      }
277
      else {
278
         /* different src/dst buffers */
279
         ctx->Driver.MapRenderbuffer(ctx, readRb,
280
                                     srcXpos, srcYpos,
281
                                     srcWidth, srcHeight,
282
                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride);
283
         if (!srcMap) {
284
            goto fail_no_memory;
285
         }
286
         ctx->Driver.MapRenderbuffer(ctx, drawRb,
287
                                     dstXpos, dstYpos,
288
                                     dstWidth, dstHeight,
289
                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
290
         if (!dstMap) {
291
            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
292
            goto fail_no_memory;
293
         }
294
      }
295
 
296
      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
297
         GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
298
         GLint srcRow = IROUND(srcRowF);
299
         GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
300
 
301
         ASSERT(srcRow >= 0);
302
         ASSERT(srcRow < srcHeight);
303
 
304
         if (invertY) {
305
            srcRow = srcHeight - 1 - srcRow;
306
         }
307
 
308
         /* get pixel row from source and resample to match dest width */
309
         if (prevY != srcRow) {
310
            GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
311
 
312
            switch (mode) {
313
            case DIRECT:
314
               memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
315
               break;
316
            case UNPACK_RGBA_FLOAT:
317
               _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
318
                                     srcBuffer);
319
               break;
320
            case UNPACK_Z_FLOAT:
321
               _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
322
                                        srcBuffer);
323
               break;
324
            case UNPACK_Z_INT:
325
               _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
326
                                       srcBuffer);
327
               break;
328
            case UNPACK_S:
329
               _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
330
                                              srcRowStart, srcBuffer);
331
               break;
332
            }
333
 
334
            (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
335
            prevY = srcRow;
336
         }
337
 
338
         /* store pixel row in destination */
339
         switch (mode) {
340
         case DIRECT:
341
            memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
342
            break;
343
         case UNPACK_RGBA_FLOAT:
344
            _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
345
                                      dstRowStart);
346
            break;
347
         case UNPACK_Z_FLOAT:
348
            _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
349
                                   dstRowStart);
350
            break;
351
         case UNPACK_Z_INT:
352
            _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
353
                                  dstRowStart);
354
            break;
355
         case UNPACK_S:
356
            _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
357
                                         dstRowStart);
358
            break;
359
         }
360
      }
361
 
362
      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
363
      if (drawRb != readRb) {
364
         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
365
      }
366
   }
367
 
368
fail:
369
   free(srcBuffer);
370
   free(dstBuffer);
371
   return;
372
 
373
fail_no_memory:
374
   free(srcBuffer);
375
   free(dstBuffer);
376
   _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
377
}
378
 
379
 
380
 
381
#define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
382
 
383
static inline GLfloat
384
lerp_2d(GLfloat a, GLfloat b,
385
        GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
386
{
387
   const GLfloat temp0 = LERP(a, v00, v10);
388
   const GLfloat temp1 = LERP(a, v01, v11);
389
   return LERP(b, temp0, temp1);
390
}
391
 
392
 
393
/**
394
 * Bilinear interpolation of two source rows.
395
 * GLubyte pixels.
396
 */
397
static void
398
resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
399
                       const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
400
                       GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
401
{
402
   const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
403
   const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
404
   GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
405
   GLint dstCol;
406
 
407
   for (dstCol = 0; dstCol < dstWidth; dstCol++) {
408
      const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
409
      GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
410
      GLint srcCol1 = srcCol0 + 1;
411
      GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
412
      GLfloat red, green, blue, alpha;
413
 
414
      ASSERT(srcCol0 < srcWidth);
415
      ASSERT(srcCol1 <= srcWidth);
416
 
417
      if (srcCol1 == srcWidth) {
418
         /* last column fudge */
419
         srcCol1--;
420
         colWeight = 0.0;
421
      }
422
 
423
      if (flip) {
424
         srcCol0 = srcWidth - 1 - srcCol0;
425
         srcCol1 = srcWidth - 1 - srcCol1;
426
      }
427
 
428
      red = lerp_2d(colWeight, rowWeight,
429
                    srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
430
                    srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
431
      green = lerp_2d(colWeight, rowWeight,
432
                    srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
433
                    srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
434
      blue = lerp_2d(colWeight, rowWeight,
435
                    srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
436
                    srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
437
      alpha = lerp_2d(colWeight, rowWeight,
438
                    srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
439
                    srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
440
 
441
      dstColor[dstCol][RCOMP] = IFLOOR(red);
442
      dstColor[dstCol][GCOMP] = IFLOOR(green);
443
      dstColor[dstCol][BCOMP] = IFLOOR(blue);
444
      dstColor[dstCol][ACOMP] = IFLOOR(alpha);
445
   }
446
}
447
 
448
 
449
/**
450
 * Bilinear interpolation of two source rows.  floating point pixels.
451
 */
452
static void
453
resample_linear_row_float(GLint srcWidth, GLint dstWidth,
454
                          const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
455
                          GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
456
{
457
   const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
458
   const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
459
   GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
460
   GLint dstCol;
461
 
462
   for (dstCol = 0; dstCol < dstWidth; dstCol++) {
463
      const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
464
      GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
465
      GLint srcCol1 = srcCol0 + 1;
466
      GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
467
      GLfloat red, green, blue, alpha;
468
 
469
      ASSERT(srcCol0 < srcWidth);
470
      ASSERT(srcCol1 <= srcWidth);
471
 
472
      if (srcCol1 == srcWidth) {
473
         /* last column fudge */
474
         srcCol1--;
475
         colWeight = 0.0;
476
      }
477
 
478
      if (flip) {
479
         srcCol0 = srcWidth - 1 - srcCol0;
480
         srcCol1 = srcWidth - 1 - srcCol1;
481
      }
482
 
483
      red = lerp_2d(colWeight, rowWeight,
484
                    srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
485
                    srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
486
      green = lerp_2d(colWeight, rowWeight,
487
                    srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
488
                    srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
489
      blue = lerp_2d(colWeight, rowWeight,
490
                    srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
491
                    srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
492
      alpha = lerp_2d(colWeight, rowWeight,
493
                    srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
494
                    srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
495
 
496
      dstColor[dstCol][RCOMP] = red;
497
      dstColor[dstCol][GCOMP] = green;
498
      dstColor[dstCol][BCOMP] = blue;
499
      dstColor[dstCol][ACOMP] = alpha;
500
   }
501
}
502
 
503
 
504
 
505
/**
506
 * Bilinear filtered blit (color only, non-integer values).
507
 */
508
static void
509
blit_linear(struct gl_context *ctx,
510
            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
511
            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
512
{
513
   struct gl_framebuffer *drawFb = ctx->DrawBuffer;
514
   struct gl_framebuffer *readFb = ctx->ReadBuffer;
515
   struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
516
   struct gl_renderbuffer_attachment *readAtt =
517
      &readFb->Attachment[readFb->_ColorReadBufferIndex];
518
 
519
   const GLint srcWidth = ABS(srcX1 - srcX0);
520
   const GLint dstWidth = ABS(dstX1 - dstX0);
521
   const GLint srcHeight = ABS(srcY1 - srcY0);
522
   const GLint dstHeight = ABS(dstY1 - dstY0);
523
 
524
   const GLint srcXpos = MIN2(srcX0, srcX1);
525
   const GLint srcYpos = MIN2(srcY0, srcY1);
526
   const GLint dstXpos = MIN2(dstX0, dstX1);
527
   const GLint dstYpos = MIN2(dstY0, dstY1);
528
 
529
   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
530
   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
531
 
532
   GLint dstRow;
533
 
534
   GLint pixelSize;
535
   GLvoid *srcBuffer0, *srcBuffer1;
536
   GLint srcBufferY0 = -1, srcBufferY1 = -1;
537
   GLvoid *dstBuffer;
538
 
539
   gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
540
   GLuint bpp = _mesa_get_format_bytes(readFormat);
541
 
542
   GLenum pixelType;
543
 
544
   GLubyte *srcMap, *dstMap;
545
   GLint srcRowStride, dstRowStride;
546
   GLuint i;
547
 
548
 
549
   /* Determine datatype for resampling */
550
   if (_mesa_get_format_max_bits(readFormat) == 8 &&
551
       _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
552
      pixelType = GL_UNSIGNED_BYTE;
553
      pixelSize = 4 * sizeof(GLubyte);
554
   }
555
   else {
556
      pixelType = GL_FLOAT;
557
      pixelSize = 4 * sizeof(GLfloat);
558
   }
559
 
560
   /* Allocate the src/dst row buffers.
561
    * Keep two adjacent src rows around for bilinear sampling.
562
    */
563
   srcBuffer0 = malloc(pixelSize * srcWidth);
564
   srcBuffer1 = malloc(pixelSize * srcWidth);
565
   dstBuffer = malloc(pixelSize * dstWidth);
566
   if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
567
      goto fail_no_memory;
568
   }
569
 
570
   for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
571
      GLint idx = drawFb->_ColorDrawBufferIndexes[i];
572
      struct gl_renderbuffer_attachment *drawAtt;
573
      struct gl_renderbuffer *drawRb;
574
      gl_format drawFormat;
575
 
576
      if (idx == -1)
577
         continue;
578
 
579
      drawAtt = &drawFb->Attachment[idx];
580
      drawRb = drawAtt->Renderbuffer;
581
      if (!drawRb)
582
         continue;
583
 
584
      drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
585
 
586
      /*
587
       * Map src / dst renderbuffers
588
       */
589
      if ((readRb == drawRb) ||
590
          (readAtt->Texture && drawAtt->Texture &&
591
           (readAtt->Texture == drawAtt->Texture))) {
592
         /* map whole buffer for read/write */
593
         ctx->Driver.MapRenderbuffer(ctx, readRb,
594
                                     0, 0, readRb->Width, readRb->Height,
595
                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
596
                                     &srcMap, &srcRowStride);
597
         if (!srcMap) {
598
            goto fail_no_memory;
599
         }
600
 
601
         dstMap = srcMap;
602
         dstRowStride = srcRowStride;
603
      }
604
      else {
605
         /* different src/dst buffers */
606
         /* XXX with a bit of work we could just map the regions to be
607
          * read/written instead of the whole buffers.
608
          */
609
         ctx->Driver.MapRenderbuffer(ctx, readRb,
610
                                     0, 0, readRb->Width, readRb->Height,
611
                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride);
612
         if (!srcMap) {
613
            goto fail_no_memory;
614
         }
615
         ctx->Driver.MapRenderbuffer(ctx, drawRb,
616
                                     0, 0, drawRb->Width, drawRb->Height,
617
                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
618
         if (!dstMap) {
619
            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
620
            goto fail_no_memory;
621
         }
622
      }
623
 
624
      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
625
         const GLint dstY = dstYpos + dstRow;
626
         GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
627
         GLint srcRow0 = MAX2(0, IFLOOR(srcRow));
628
         GLint srcRow1 = srcRow0 + 1;
629
         GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
630
 
631
         if (srcRow1 == srcHeight) {
632
            /* last row fudge */
633
            srcRow1 = srcRow0;
634
            rowWeight = 0.0;
635
         }
636
 
637
         if (invertY) {
638
            srcRow0 = srcHeight - 1 - srcRow0;
639
            srcRow1 = srcHeight - 1 - srcRow1;
640
         }
641
 
642
         srcY0 = srcYpos + srcRow0;
643
         srcY1 = srcYpos + srcRow1;
644
 
645
         /* get the two source rows */
646
         if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
647
            /* use same source row buffers again */
648
         }
649
         else if (srcY0 == srcBufferY1) {
650
            /* move buffer1 into buffer0 by swapping pointers */
651
            GLvoid *tmp = srcBuffer0;
652
            srcBuffer0 = srcBuffer1;
653
            srcBuffer1 = tmp;
654
            /* get y1 row */
655
            {
656
               GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
657
               if (pixelType == GL_UNSIGNED_BYTE) {
658
                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
659
                                              src, srcBuffer1);
660
               }
661
               else {
662
                  _mesa_unpack_rgba_row(readFormat, srcWidth,
663
                                        src, srcBuffer1);
664
               }
665
            }
666
            srcBufferY0 = srcY0;
667
            srcBufferY1 = srcY1;
668
         }
669
         else {
670
            /* get both new rows */
671
            {
672
               GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
673
               GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
674
               if (pixelType == GL_UNSIGNED_BYTE) {
675
                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
676
                                              src0, srcBuffer0);
677
                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
678
                                              src1, srcBuffer1);
679
               }
680
               else {
681
                  _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
682
                  _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
683
               }
684
            }
685
            srcBufferY0 = srcY0;
686
            srcBufferY1 = srcY1;
687
         }
688
 
689
         if (pixelType == GL_UNSIGNED_BYTE) {
690
            resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
691
                                   dstBuffer, invertX, rowWeight);
692
         }
693
         else {
694
            resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
695
                                      dstBuffer, invertX, rowWeight);
696
         }
697
 
698
         /* store pixel row in destination */
699
         {
700
            GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
701
            if (pixelType == GL_UNSIGNED_BYTE) {
702
               _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
703
            }
704
            else {
705
               _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
706
            }
707
         }
708
      }
709
 
710
      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
711
      if (drawRb != readRb) {
712
         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
713
      }
714
   }
715
 
716
   free(srcBuffer0);
717
   free(srcBuffer1);
718
   free(dstBuffer);
719
   return;
720
 
721
fail_no_memory:
722
   free(srcBuffer0);
723
   free(srcBuffer1);
724
   free(dstBuffer);
725
   _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
726
}
727
 
728
 
729
 
730
/**
731
 * Software fallback for glBlitFramebufferEXT().
732
 */
733
void
734
_swrast_BlitFramebuffer(struct gl_context *ctx,
735
                        GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
736
                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
737
                        GLbitfield mask, GLenum filter)
738
{
739
   static const GLbitfield buffers[3] = {
740
      GL_COLOR_BUFFER_BIT,
741
      GL_DEPTH_BUFFER_BIT,
742
      GL_STENCIL_BUFFER_BIT
743
   };
744
   static const GLenum buffer_enums[3] = {
745
      GL_COLOR,
746
      GL_DEPTH,
747
      GL_STENCIL,
748
   };
749
   GLint i;
750
 
751
   if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
752
                        &dstX0, &dstY0, &dstX1, &dstY1)) {
753
      return;
754
   }
755
 
756
   if (SWRAST_CONTEXT(ctx)->NewState)
757
      _swrast_validate_derived(ctx);
758
 
759
   /* First, try covering whatever buffers possible using the fast 1:1 copy
760
    * path.
761
    */
762
   if (srcX1 - srcX0 == dstX1 - dstX0 &&
763
       srcY1 - srcY0 == dstY1 - dstY0 &&
764
       srcX0 < srcX1 &&
765
       srcY0 < srcY1 &&
766
       dstX0 < dstX1 &&
767
       dstY0 < dstY1) {
768
      for (i = 0; i < 3; i++) {
769
         if (mask & buffers[i]) {
770
	    if (swrast_fast_copy_pixels(ctx,
771
					srcX0, srcY0,
772
					srcX1 - srcX0, srcY1 - srcY0,
773
					dstX0, dstY0,
774
					buffer_enums[i])) {
775
	       mask &= ~buffers[i];
776
	    }
777
	 }
778
      }
779
 
780
      if (!mask)
781
	 return;
782
   }
783
 
784
   if (filter == GL_NEAREST) {
785
      for (i = 0; i < 3; i++) {
786
	 if (mask & buffers[i]) {
787
	    blit_nearest(ctx,  srcX0, srcY0, srcX1, srcY1,
788
			 dstX0, dstY0, dstX1, dstY1, buffers[i]);
789
	 }
790
      }
791
   }
792
   else {
793
      ASSERT(filter == GL_LINEAR);
794
      if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
795
	 blit_linear(ctx,  srcX0, srcY0, srcX1, srcY1,
796
		     dstX0, dstY0, dstX1, dstY1);
797
      }
798
   }
799
 
800
}