Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2007  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/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 = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */
140
141    if (overlapping) {
142       tmpImage = (GLfloat *) 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, GL_FLOAT, 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 < MAX_WIDTH);
162
163    for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
164       GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_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, GL_FLOAT, 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->_DepthBuffer;
249    GLfloat *p, *tmpImage;
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 = (GLfloat *) 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    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
307       GLfloat depth[MAX_WIDTH];
308       /* get depth values */
309       if (overlapping) {
310          memcpy(depth, p, width * sizeof(GLfloat));
311          p += width;
312       }
313       else {
314          _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
315       }
316
317       /* apply scale and bias */
318       scale_and_bias_z(ctx, width, depth, span.array->z);
319
320       /* write depth values */
321       span.x = destx;
322       span.y = dy;
323       span.end = width;
324       if (zoom)
325          _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
326       else
327          _swrast_write_rgba_span(ctx, &span);
328    }
329
330    if (overlapping)
331       free(tmpImage);
332 }
333
334
335
336 static void
337 copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
338                      GLint width, GLint height,
339                      GLint destx, GLint desty )
340 {
341    struct gl_framebuffer *fb = ctx->ReadBuffer;
342    struct gl_renderbuffer *rb = fb->_StencilBuffer;
343    GLint sy, dy, stepy;
344    GLint j;
345    GLstencil *p, *tmpImage;
346    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
347    GLint overlapping;
348
349    if (!rb) {
350       /* no readbuffer - OK */
351       return;
352    }
353
354    if (ctx->DrawBuffer == ctx->ReadBuffer) {
355       overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
356                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
357    }
358    else {
359       overlapping = GL_FALSE;
360    }
361
362    /* Determine if copy should be bottom-to-top or top-to-bottom */
363    if (!overlapping && srcy < desty) {
364       /* top-down  max-to-min */
365       sy = srcy + height - 1;
366       dy = desty + height - 1;
367       stepy = -1;
368    }
369    else {
370       /* bottom-up  min-to-max */
371       sy = srcy;
372       dy = desty;
373       stepy = 1;
374    }
375
376    if (overlapping) {
377       GLint ssy = sy;
378       tmpImage = (GLstencil *) malloc(width * height * sizeof(GLstencil));
379       if (!tmpImage) {
380          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
381          return;
382       }
383       p = tmpImage;
384       for (j = 0; j < height; j++, ssy += stepy) {
385          _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
386          p += width;
387       }
388       p = tmpImage;
389    }
390    else {
391       tmpImage = NULL;  /* silence compiler warning */
392       p = NULL;
393    }
394
395    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
396       GLstencil stencil[MAX_WIDTH];
397
398       /* Get stencil values */
399       if (overlapping) {
400          memcpy(stencil, p, width * sizeof(GLstencil));
401          p += width;
402       }
403       else {
404          _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
405       }
406
407       _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
408
409       /* Write stencil values */
410       if (zoom) {
411          _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
412                                            destx, dy, stencil);
413       }
414       else {
415          _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
416       }
417    }
418
419    if (overlapping)
420       free(tmpImage);
421 }
422
423
424 /**
425  * This isn't terribly efficient.  If a driver really has combined
426  * depth/stencil buffers the driver should implement an optimized
427  * CopyPixels function.
428  */
429 static void
430 copy_depth_stencil_pixels(struct gl_context *ctx,
431                           const GLint srcX, const GLint srcY,
432                           const GLint width, const GLint height,
433                           const GLint destX, const GLint destY)
434 {
435    struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
436    GLint sy, dy, stepy;
437    GLint j;
438    GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
439    GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
440    const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
441    const GLuint stencilMask = ctx->Stencil.WriteMask[0];
442    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
443    const GLboolean scaleOrBias
444       = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
445    GLint overlapping;
446
447    depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
448    depthReadRb = ctx->ReadBuffer->_DepthBuffer;
449    stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
450
451    ASSERT(depthDrawRb);
452    ASSERT(depthReadRb);
453    ASSERT(stencilReadRb);
454
455    if (ctx->DrawBuffer == ctx->ReadBuffer) {
456       overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
457                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
458    }
459    else {
460       overlapping = GL_FALSE;
461    }
462
463    /* Determine if copy should be bottom-to-top or top-to-bottom */
464    if (!overlapping && srcY < destY) {
465       /* top-down  max-to-min */
466       sy = srcY + height - 1;
467       dy = destY + height - 1;
468       stepy = -1;
469    }
470    else {
471       /* bottom-up  min-to-max */
472       sy = srcY;
473       dy = destY;
474       stepy = 1;
475    }
476
477    if (overlapping) {
478       GLint ssy = sy;
479
480       if (stencilMask != 0x0) {
481          tempStencilImage
482             = (GLstencil *) malloc(width * height * sizeof(GLstencil));
483          if (!tempStencilImage) {
484             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
485             return;
486          }
487
488          /* get copy of stencil pixels */
489          stencilPtr = tempStencilImage;
490          for (j = 0; j < height; j++, ssy += stepy) {
491             _swrast_read_stencil_span(ctx, stencilReadRb,
492                                       width, srcX, ssy, stencilPtr);
493             stencilPtr += width;
494          }
495          stencilPtr = tempStencilImage;
496       }
497
498       if (ctx->Depth.Mask) {
499          tempDepthImage
500             = (GLfloat *) malloc(width * height * sizeof(GLfloat));
501          if (!tempDepthImage) {
502             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
503             free(tempStencilImage);
504             return;
505          }
506
507          /* get copy of depth pixels */
508          depthPtr = tempDepthImage;
509          for (j = 0; j < height; j++, ssy += stepy) {
510             _swrast_read_depth_span_float(ctx, depthReadRb,
511                                           width, srcX, ssy, depthPtr);
512             depthPtr += width;
513          }
514          depthPtr = tempDepthImage;
515       }
516    }
517
518    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
519       if (stencilMask != 0x0) {
520          GLstencil stencil[MAX_WIDTH];
521
522          /* Get stencil values */
523          if (overlapping) {
524             memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
525             stencilPtr += width;
526          }
527          else {
528             _swrast_read_stencil_span(ctx, stencilReadRb,
529                                       width, srcX, sy, stencil);
530          }
531
532          _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
533
534          /* Write values */
535          if (zoom) {
536             _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
537                                               destX, dy, stencil);
538          }
539          else {
540             _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
541          }
542       }
543
544       if (ctx->Depth.Mask) {
545          GLfloat depth[MAX_WIDTH];
546          GLuint zVals32[MAX_WIDTH];
547          GLushort zVals16[MAX_WIDTH];
548          GLvoid *zVals;
549          GLuint zBytes;
550
551          /* get depth values */
552          if (overlapping) {
553             memcpy(depth, depthPtr, width * sizeof(GLfloat));
554             depthPtr += width;
555          }
556          else {
557             _swrast_read_depth_span_float(ctx, depthReadRb,
558                                           width, srcX, sy, depth);
559          }
560
561          /* scale & bias */
562          if (scaleOrBias) {
563             _mesa_scale_and_bias_depth(ctx, width, depth);
564          }
565          /* convert to integer Z values */
566          if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
567             GLint k;
568             for (k = 0; k < width; k++)
569                zVals16[k] = (GLushort) (depth[k] * depthScale);
570             zVals = zVals16;
571             zBytes = 2;
572          }
573          else {
574             GLint k;
575             for (k = 0; k < width; k++)
576                zVals32[k] = (GLuint) (depth[k] * depthScale);
577             zVals = zVals32;
578             zBytes = 4;
579          }
580
581          /* Write values */
582          if (zoom) {
583             _swrast_write_zoomed_z_span(ctx, destX, destY, width,
584                                         destX, dy, zVals);
585          }
586          else {
587             _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
588          }
589       }
590    }
591
592    if (tempStencilImage)
593       free(tempStencilImage);
594
595    if (tempDepthImage)
596       free(tempDepthImage);
597 }
598
599
600
601 /**
602  * Try to do a fast copy pixels.
603  */
604 static GLboolean
605 fast_copy_pixels(struct gl_context *ctx,
606                  GLint srcX, GLint srcY, GLsizei width, GLsizei height,
607                  GLint dstX, GLint dstY, GLenum type)
608 {
609    struct gl_framebuffer *srcFb = ctx->ReadBuffer;
610    struct gl_framebuffer *dstFb = ctx->DrawBuffer;
611    struct gl_renderbuffer *srcRb, *dstRb;
612    GLint row, yStep;
613
614    if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
615        ctx->Pixel.ZoomX != 1.0F ||
616        ctx->Pixel.ZoomY != 1.0F ||
617        ctx->_ImageTransferState) {
618       /* can't handle these */
619       return GL_FALSE;
620    }
621
622    if (type == GL_COLOR) {
623       if (dstFb->_NumColorDrawBuffers != 1)
624          return GL_FALSE;
625       srcRb = srcFb->_ColorReadBuffer;
626       dstRb = dstFb->_ColorDrawBuffers[0];
627    }
628    else if (type == GL_STENCIL) {
629       srcRb = srcFb->_StencilBuffer;
630       dstRb = dstFb->_StencilBuffer;
631    }
632    else if (type == GL_DEPTH) {
633       srcRb = srcFb->_DepthBuffer;
634       dstRb = dstFb->_DepthBuffer;
635    }
636    else {
637       ASSERT(type == GL_DEPTH_STENCIL_EXT);
638       /* XXX correct? */
639       srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
640       dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
641    }
642
643    /* src and dst renderbuffers must be same format and type */
644    if (!srcRb || !dstRb ||
645        srcRb->DataType != dstRb->DataType ||
646        srcRb->_BaseFormat != dstRb->_BaseFormat) {
647       return GL_FALSE;
648    }
649
650    /* clipping not supported */
651    if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
652        srcY < 0 || srcY + height > (GLint) srcFb->Height ||
653        dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
654        dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
655       return GL_FALSE;
656    }
657
658    /* overlapping src/dst doesn't matter, just determine Y direction */
659    if (srcY < dstY) {
660       /* top-down  max-to-min */
661       srcY = srcY + height - 1;
662       dstY = dstY + height - 1;
663       yStep = -1;
664    }
665    else {
666       /* bottom-up  min-to-max */
667       yStep = 1;
668    }
669
670    for (row = 0; row < height; row++) {
671       GLuint temp[MAX_WIDTH][4];
672       srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
673       dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
674       srcY += yStep;
675       dstY += yStep;
676    }
677
678    return GL_TRUE;
679 }
680
681
682 /**
683  * Do software-based glCopyPixels.
684  * By time we get here, all parameters will have been error-checked.
685  */
686 void
687 _swrast_CopyPixels( struct gl_context *ctx,
688                     GLint srcx, GLint srcy, GLsizei width, GLsizei height,
689                     GLint destx, GLint desty, GLenum type )
690 {
691    SWcontext *swrast = SWRAST_CONTEXT(ctx);
692    swrast_render_start(ctx);
693       
694    if (!_mesa_check_conditional_render(ctx))
695       return; /* don't copy */
696
697    if (swrast->NewState)
698       _swrast_validate_derived( ctx );
699
700    if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
701       switch (type) {
702       case GL_COLOR:
703          copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
704          break;
705       case GL_DEPTH:
706          copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
707          break;
708       case GL_STENCIL:
709          copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
710          break;
711       case GL_DEPTH_STENCIL_EXT:
712          copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
713          break;
714       default:
715          _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
716       }
717    }
718
719    swrast_render_finish(ctx);
720 }