Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2007  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/context.h"
28
#include "main/colormac.h"
29
#include "main/condrender.h"
30
#include "main/macros.h"
31
#include "main/pixeltransfer.h"
32
#include "main/imports.h"
33
 
34
#include "s_context.h"
35
#include "s_depth.h"
36
#include "s_span.h"
37
#include "s_stencil.h"
38
#include "s_zoom.h"
39
 
40
 
41
 
42
/**
43
 * Determine if there's overlap in an image copy.
44
 * This test also compensates for the fact that copies are done from
45
 * bottom to top and overlaps can sometimes be handled correctly
46
 * without making a temporary image copy.
47
 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
48
 */
49
static GLboolean
50
regions_overlap(GLint srcx, GLint srcy,
51
                GLint dstx, GLint dsty,
52
                GLint width, GLint height,
53
                GLfloat zoomX, GLfloat zoomY)
54
{
55
   if (zoomX == 1.0 && zoomY == 1.0) {
56
      /* no zoom */
57
      if (srcx >= dstx + width || (srcx + width <= dstx)) {
58
         return GL_FALSE;
59
      }
60
      else if (srcy < dsty) { /* this is OK */
61
         return GL_FALSE;
62
      }
63
      else if (srcy > dsty + height) {
64
         return GL_FALSE;
65
      }
66
      else {
67
         return GL_TRUE;
68
      }
69
   }
70
   else {
71
      /* add one pixel of slop when zooming, just to be safe */
72
      if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
73
         /* src is completely right of dest */
74
         return GL_FALSE;
75
      }
76
      else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
77
         /* src is completely left of dest */
78
         return GL_FALSE;
79
      }
80
      else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
81
         /* src is completely below dest */
82
         return GL_FALSE;
83
      }
84
      else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
85
         /* src is completely above dest */
86
         return GL_FALSE;
87
      }
88
      else {
89
         return GL_TRUE;
90
      }
91
   }
92
}
93
 
94
 
95
/**
96
 * RGBA copypixels
97
 */
98
static void
99
copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
100
                 GLint width, GLint height, GLint destx, GLint desty)
101
{
102
   GLfloat *tmpImage, *p;
103
   GLint sy, dy, stepy, row;
104
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
105
   GLint overlapping;
106
   GLuint transferOps = ctx->_ImageTransferState;
107
   SWspan span;
108
 
109
   if (!ctx->ReadBuffer->_ColorReadBuffer) {
110
      /* no readbuffer - OK */
111
      return;
112
   }
113
 
114
   if (ctx->DrawBuffer == ctx->ReadBuffer) {
115
      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
116
                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
117
   }
118
   else {
119
      overlapping = GL_FALSE;
120
   }
121
 
122
   /* Determine if copy should be done bottom-to-top or top-to-bottom */
123
   if (!overlapping && srcy < desty) {
124
      /* top-down  max-to-min */
125
      sy = srcy + height - 1;
126
      dy = desty + height - 1;
127
      stepy = -1;
128
   }
129
   else {
130
      /* bottom-up  min-to-max */
131
      sy = srcy;
132
      dy = desty;
133
      stepy = 1;
134
   }
135
 
136
   INIT_SPAN(span, GL_BITMAP);
137
   _swrast_span_default_attribs(ctx, &span);
138
   span.arrayMask = SPAN_RGBA;
139
   span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */
140
 
141
   if (overlapping) {
142
      tmpImage = malloc(width * height * sizeof(GLfloat) * 4);
143
      if (!tmpImage) {
144
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
145
         return;
146
      }
147
      /* read the source image as RGBA/float */
148
      p = tmpImage;
149
      for (row = 0; row < height; row++) {
150
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
151
                                 width, srcx, sy + row, p );
152
         p += width * 4;
153
      }
154
      p = tmpImage;
155
   }
156
   else {
157
      tmpImage = NULL;  /* silence compiler warnings */
158
      p = NULL;
159
   }
160
 
161
   ASSERT(width < SWRAST_MAX_WIDTH);
162
 
163
   for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
164
      GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0];
165
 
166
      /* Get row/span of source pixels */
167
      if (overlapping) {
168
         /* get from buffered image */
169
         memcpy(rgba, p, width * sizeof(GLfloat) * 4);
170
         p += width * 4;
171
      }
172
      else {
173
         /* get from framebuffer */
174
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
175
                                 width, srcx, sy, rgba );
176
      }
177
 
178
      if (transferOps) {
179
         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
180
                                       (GLfloat (*)[4]) rgba);
181
      }
182
 
183
      /* Write color span */
184
      span.x = destx;
185
      span.y = dy;
186
      span.end = width;
187
      span.array->ChanType = GL_FLOAT;
188
      if (zoom) {
189
         _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
190
      }
191
      else {
192
         _swrast_write_rgba_span(ctx, &span);
193
      }
194
   }
195
 
196
   span.array->ChanType = CHAN_TYPE; /* restore */
197
 
198
   if (overlapping)
199
      free(tmpImage);
200
}
201
 
202
 
203
/**
204
 * Convert floating point Z values to integer Z values with pixel transfer's
205
 * Z scale and bias.
206
 */
207
static void
208
scale_and_bias_z(struct gl_context *ctx, GLuint width,
209
                 const GLfloat depth[], GLuint z[])
210
{
211
   const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
212
   GLuint i;
213
 
214
   if (depthMax <= 0xffffff &&
215
       ctx->Pixel.DepthScale == 1.0 &&
216
       ctx->Pixel.DepthBias == 0.0) {
217
      /* no scale or bias and no clamping and no worry of overflow */
218
      const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
219
      for (i = 0; i < width; i++) {
220
         z[i] = (GLuint) (depth[i] * depthMaxF);
221
      }
222
   }
223
   else {
224
      /* need to be careful with overflow */
225
      const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
226
      for (i = 0; i < width; i++) {
227
         GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
228
         d = CLAMP(d, 0.0, 1.0) * depthMaxF;
229
         if (d >= depthMaxF)
230
            z[i] = depthMax;
231
         else
232
            z[i] = (GLuint) d;
233
      }
234
   }
235
}
236
 
237
 
238
 
239
/*
240
 * TODO: Optimize!!!!
241
 */
242
static void
243
copy_depth_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
244
                   GLint width, GLint height,
245
                   GLint destx, GLint desty )
246
{
247
   struct gl_framebuffer *fb = ctx->ReadBuffer;
248
   struct gl_renderbuffer *readRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
249
   GLfloat *p, *tmpImage, *depth;
250
   GLint sy, dy, stepy;
251
   GLint j;
252
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
253
   GLint overlapping;
254
   SWspan span;
255
 
256
   if (!readRb) {
257
      /* no readbuffer - OK */
258
      return;
259
   }
260
 
261
   INIT_SPAN(span, GL_BITMAP);
262
   _swrast_span_default_attribs(ctx, &span);
263
   span.arrayMask = SPAN_Z;
264
 
265
   if (ctx->DrawBuffer == ctx->ReadBuffer) {
266
      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
267
                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
268
   }
269
   else {
270
      overlapping = GL_FALSE;
271
   }
272
 
273
   /* Determine if copy should be bottom-to-top or top-to-bottom */
274
   if (!overlapping && srcy < desty) {
275
      /* top-down  max-to-min */
276
      sy = srcy + height - 1;
277
      dy = desty + height - 1;
278
      stepy = -1;
279
   }
280
   else {
281
      /* bottom-up  min-to-max */
282
      sy = srcy;
283
      dy = desty;
284
      stepy = 1;
285
   }
286
 
287
   if (overlapping) {
288
      GLint ssy = sy;
289
      tmpImage = malloc(width * height * sizeof(GLfloat));
290
      if (!tmpImage) {
291
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
292
         return;
293
      }
294
      p = tmpImage;
295
      for (j = 0; j < height; j++, ssy += stepy) {
296
         _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
297
         p += width;
298
      }
299
      p = tmpImage;
300
   }
301
   else {
302
      tmpImage = NULL;  /* silence compiler warning */
303
      p = NULL;
304
   }
305
 
306
   depth = malloc(width * sizeof(GLfloat));
307
   if (!depth) {
308
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
309
      goto end;
310
   }
311
 
312
   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
313
      /* get depth values */
314
      if (overlapping) {
315
         memcpy(depth, p, width * sizeof(GLfloat));
316
         p += width;
317
      }
318
      else {
319
         _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
320
      }
321
 
322
      /* apply scale and bias */
323
      scale_and_bias_z(ctx, width, depth, span.array->z);
324
 
325
      /* write depth values */
326
      span.x = destx;
327
      span.y = dy;
328
      span.end = width;
329
      if (zoom)
330
         _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
331
      else
332
         _swrast_write_rgba_span(ctx, &span);
333
   }
334
 
335
   free(depth);
336
 
337
end:
338
   if (overlapping)
339
      free(tmpImage);
340
}
341
 
342
 
343
 
344
static void
345
copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
346
                     GLint width, GLint height,
347
                     GLint destx, GLint desty )
348
{
349
   struct gl_framebuffer *fb = ctx->ReadBuffer;
350
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
351
   GLint sy, dy, stepy;
352
   GLint j;
353
   GLubyte *p, *tmpImage, *stencil;
354
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
355
   GLint overlapping;
356
 
357
   if (!rb) {
358
      /* no readbuffer - OK */
359
      return;
360
   }
361
 
362
   if (ctx->DrawBuffer == ctx->ReadBuffer) {
363
      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
364
                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
365
   }
366
   else {
367
      overlapping = GL_FALSE;
368
   }
369
 
370
   /* Determine if copy should be bottom-to-top or top-to-bottom */
371
   if (!overlapping && srcy < desty) {
372
      /* top-down  max-to-min */
373
      sy = srcy + height - 1;
374
      dy = desty + height - 1;
375
      stepy = -1;
376
   }
377
   else {
378
      /* bottom-up  min-to-max */
379
      sy = srcy;
380
      dy = desty;
381
      stepy = 1;
382
   }
383
 
384
   if (overlapping) {
385
      GLint ssy = sy;
386
      tmpImage = malloc(width * height * sizeof(GLubyte));
387
      if (!tmpImage) {
388
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
389
         return;
390
      }
391
      p = tmpImage;
392
      for (j = 0; j < height; j++, ssy += stepy) {
393
         _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
394
         p += width;
395
      }
396
      p = tmpImage;
397
   }
398
   else {
399
      tmpImage = NULL;  /* silence compiler warning */
400
      p = NULL;
401
   }
402
 
403
   stencil = malloc(width * sizeof(GLubyte));
404
   if (!stencil) {
405
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
406
      goto end;
407
   }
408
 
409
   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
410
      /* Get stencil values */
411
      if (overlapping) {
412
         memcpy(stencil, p, width * sizeof(GLubyte));
413
         p += width;
414
      }
415
      else {
416
         _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
417
      }
418
 
419
      _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
420
 
421
      /* Write stencil values */
422
      if (zoom) {
423
         _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
424
                                           destx, dy, stencil);
425
      }
426
      else {
427
         _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
428
      }
429
   }
430
 
431
   free(stencil);
432
 
433
end:
434
   if (overlapping)
435
      free(tmpImage);
436
}
437
 
438
 
439
/**
440
 * Try to do a fast 1:1 blit with memcpy.
441
 * \return GL_TRUE if successful, GL_FALSE otherwise.
442
 */
443
GLboolean
444
swrast_fast_copy_pixels(struct gl_context *ctx,
445
			GLint srcX, GLint srcY, GLsizei width, GLsizei height,
446
			GLint dstX, GLint dstY, GLenum type)
447
{
448
   struct gl_framebuffer *srcFb = ctx->ReadBuffer;
449
   struct gl_framebuffer *dstFb = ctx->DrawBuffer;
450
   struct gl_renderbuffer *srcRb, *dstRb;
451
   GLint row;
452
   GLuint pixelBytes, widthInBytes;
453
   GLubyte *srcMap, *dstMap;
454
   GLint srcRowStride, dstRowStride;
455
 
456
   if (type == GL_COLOR) {
457
      if (dstFb->_NumColorDrawBuffers != 1)
458
         return GL_FALSE;
459
      srcRb = srcFb->_ColorReadBuffer;
460
      dstRb = dstFb->_ColorDrawBuffers[0];
461
   }
462
   else if (type == GL_STENCIL) {
463
      srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer;
464
      dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer;
465
   }
466
   else if (type == GL_DEPTH) {
467
      srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
468
      dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
469
   }
470
   else {
471
      ASSERT(type == GL_DEPTH_STENCIL_EXT);
472
      /* XXX correct? */
473
      srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
474
      dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
475
   }
476
 
477
   /* src and dst renderbuffers must be same format */
478
   if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) {
479
      return GL_FALSE;
480
   }
481
 
482
   if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) {
483
      /* can't handle packed depth+stencil here */
484
      if (_mesa_is_format_packed_depth_stencil(srcRb->Format) ||
485
          _mesa_is_format_packed_depth_stencil(dstRb->Format))
486
         return GL_FALSE;
487
   }
488
   else if (type == GL_DEPTH_STENCIL) {
489
      /* can't handle separate depth/stencil buffers */
490
      if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer ||
491
          dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer)
492
         return GL_FALSE;
493
   }
494
 
495
   /* clipping not supported */
496
   if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
497
       srcY < 0 || srcY + height > (GLint) srcFb->Height ||
498
       dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
499
       dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
500
      return GL_FALSE;
501
   }
502
 
503
   pixelBytes = _mesa_get_format_bytes(srcRb->Format);
504
   widthInBytes = width * pixelBytes;
505
 
506
   if (srcRb == dstRb) {
507
      /* map whole buffer for read/write */
508
      /* XXX we could be clever and just map the union region of the
509
       * source and dest rects.
510
       */
511
      GLubyte *map;
512
      GLint rowStride;
513
 
514
      ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0,
515
                                  srcRb->Width, srcRb->Height,
516
                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
517
                                  &map, &rowStride);
518
      if (!map) {
519
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
520
         return GL_TRUE; /* don't retry with slow path */
521
      }
522
 
523
      srcMap = map + srcY * rowStride + srcX * pixelBytes;
524
      dstMap = map + dstY * rowStride + dstX * pixelBytes;
525
 
526
      /* this handles overlapping copies */
527
      if (srcY < dstY) {
528
         /* copy in reverse (top->down) order */
529
         srcMap += rowStride * (height - 1);
530
         dstMap += rowStride * (height - 1);
531
         srcRowStride = -rowStride;
532
         dstRowStride = -rowStride;
533
      }
534
      else {
535
         /* copy in normal (bottom->up) order */
536
         srcRowStride = rowStride;
537
         dstRowStride = rowStride;
538
      }
539
   }
540
   else {
541
      /* different src/dst buffers */
542
      ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY,
543
                                  width, height,
544
                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
545
      if (!srcMap) {
546
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
547
         return GL_TRUE; /* don't retry with slow path */
548
      }
549
      ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
550
                                  width, height,
551
                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
552
      if (!dstMap) {
553
         ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
554
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
555
         return GL_TRUE; /* don't retry with slow path */
556
      }
557
   }
558
 
559
   for (row = 0; row < height; row++) {
560
      /* memmove() in case of overlap */
561
      memmove(dstMap, srcMap, widthInBytes);
562
      dstMap += dstRowStride;
563
      srcMap += srcRowStride;
564
   }
565
 
566
   ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
567
   if (dstRb != srcRb) {
568
      ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
569
   }
570
 
571
   return GL_TRUE;
572
}
573
 
574
 
575
/**
576
 * Find/map the renderbuffer that we'll be reading from.
577
 * The swrast_render_start() function only maps the drawing buffers,
578
 * not the read buffer.
579
 */
580
static struct gl_renderbuffer *
581
map_readbuffer(struct gl_context *ctx, GLenum type)
582
{
583
   struct gl_framebuffer *fb = ctx->ReadBuffer;
584
   struct gl_renderbuffer *rb;
585
   struct swrast_renderbuffer *srb;
586
 
587
   switch (type) {
588
   case GL_COLOR:
589
      rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
590
      break;
591
   case GL_DEPTH:
592
   case GL_DEPTH_STENCIL:
593
      rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
594
      break;
595
   case GL_STENCIL:
596
      rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
597
      break;
598
   default:
599
      return NULL;
600
   }
601
 
602
   srb = swrast_renderbuffer(rb);
603
 
604
   if (!srb || srb->Map) {
605
      /* no buffer, or buffer is mapped already, we're done */
606
      return NULL;
607
   }
608
 
609
   ctx->Driver.MapRenderbuffer(ctx, rb,
610
                               0, 0, rb->Width, rb->Height,
611
                               GL_MAP_READ_BIT,
612
                               &srb->Map, &srb->RowStride);
613
 
614
   return rb;
615
}
616
 
617
 
618
/**
619
 * Do software-based glCopyPixels.
620
 * By time we get here, all parameters will have been error-checked.
621
 */
622
void
623
_swrast_CopyPixels( struct gl_context *ctx,
624
		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
625
		    GLint destx, GLint desty, GLenum type )
626
{
627
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
628
   struct gl_renderbuffer *rb;
629
 
630
   if (!_mesa_check_conditional_render(ctx))
631
      return; /* don't copy */
632
 
633
   if (swrast->NewState)
634
      _swrast_validate_derived( ctx );
635
 
636
   if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
637
	 ctx->Pixel.ZoomX != 1.0F ||
638
	 ctx->Pixel.ZoomY != 1.0F ||
639
	 ctx->_ImageTransferState) &&
640
       swrast_fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty,
641
			       type)) {
642
      /* all done */
643
      return;
644
   }
645
 
646
   swrast_render_start(ctx);
647
   rb = map_readbuffer(ctx, type);
648
 
649
   switch (type) {
650
   case GL_COLOR:
651
      copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
652
      break;
653
   case GL_DEPTH:
654
      copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
655
      break;
656
   case GL_STENCIL:
657
      copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
658
      break;
659
   case GL_DEPTH_STENCIL_EXT:
660
      /* Copy buffers separately (if the fast copy path wasn't taken) */
661
      copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
662
      copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
663
      break;
664
   default:
665
      _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
666
   }
667
 
668
   swrast_render_finish(ctx);
669
 
670
   if (rb) {
671
      struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
672
      ctx->Driver.UnmapRenderbuffer(ctx, rb);
673
      srb->Map = NULL;
674
   }
675
}