s_copypix.c revision e7e748cd04f5f014a1e4d8837ee7590d68115768
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/convolve.h"
31#include "main/image.h"
32#include "main/macros.h"
33#include "main/imports.h"
34
35#include "s_context.h"
36#include "s_depth.h"
37#include "s_span.h"
38#include "s_stencil.h"
39#include "s_zoom.h"
40
41
42
43/**
44 * Determine if there's overlap in an image copy.
45 * This test also compensates for the fact that copies are done from
46 * bottom to top and overlaps can sometimes be handled correctly
47 * without making a temporary image copy.
48 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
49 */
50static GLboolean
51regions_overlap(GLint srcx, GLint srcy,
52                GLint dstx, GLint dsty,
53                GLint width, GLint height,
54                GLfloat zoomX, GLfloat zoomY)
55{
56   if (zoomX == 1.0 && zoomY == 1.0) {
57      /* no zoom */
58      if (srcx >= dstx + width || (srcx + width <= dstx)) {
59         return GL_FALSE;
60      }
61      else if (srcy < dsty) { /* this is OK */
62         return GL_FALSE;
63      }
64      else if (srcy > dsty + height) {
65         return GL_FALSE;
66      }
67      else {
68         return GL_TRUE;
69      }
70   }
71   else {
72      /* add one pixel of slop when zooming, just to be safe */
73      if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
74         /* src is completely right of dest */
75         return GL_FALSE;
76      }
77      else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
78         /* src is completely left of dest */
79         return GL_FALSE;
80      }
81      else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
82         /* src is completely below dest */
83         return GL_FALSE;
84      }
85      else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
86         /* src is completely above dest */
87         return GL_FALSE;
88      }
89      else {
90         return GL_TRUE;
91      }
92   }
93}
94
95
96/**
97 * RGBA copypixels with convolution.
98 */
99static void
100copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
101                      GLint width, GLint height, GLint destx, GLint desty)
102{
103   GLint row;
104   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
105   const GLbitfield transferOps = ctx->_ImageTransferState;
106   const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
107      || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
108   GLfloat *dest, *tmpImage, *convImage;
109   SWspan span;
110
111   INIT_SPAN(span, GL_BITMAP);
112   _swrast_span_default_attribs(ctx, &span);
113   span.arrayMask = SPAN_RGBA;
114   span.arrayAttribs = FRAG_BIT_COL0;
115
116   /* allocate space for GLfloat image */
117   tmpImage = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
118   if (!tmpImage) {
119      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
120      return;
121   }
122   convImage = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
123   if (!convImage) {
124      free(tmpImage);
125      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
126      return;
127   }
128
129   /* read source image as float/RGBA */
130   dest = tmpImage;
131   for (row = 0; row < height; row++) {
132      _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
133                             width, srcx, srcy + row, GL_FLOAT, dest);
134      dest += 4 * width;
135   }
136
137   /* do the image transfer ops which preceed convolution */
138   for (row = 0; row < height; row++) {
139      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
140      _mesa_apply_rgba_transfer_ops(ctx,
141                                    transferOps & IMAGE_PRE_CONVOLUTION_BITS,
142                                    width, rgba);
143   }
144
145   /* do convolution */
146   if (ctx->Pixel.Convolution2DEnabled) {
147      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
148   }
149   else {
150      ASSERT(ctx->Pixel.Separable2DEnabled);
151      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
152   }
153   free(tmpImage);
154
155   /* do remaining post-convolution image transfer ops */
156   for (row = 0; row < height; row++) {
157      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
158      _mesa_apply_rgba_transfer_ops(ctx,
159                                    transferOps & IMAGE_POST_CONVOLUTION_BITS,
160                                    width, rgba);
161   }
162
163   if (!sink) {
164      /* write the new image */
165      for (row = 0; row < height; row++) {
166         const GLfloat *src = convImage + row * width * 4;
167         GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
168
169         /* copy convolved colors into span array */
170         memcpy(rgba, src, width * 4 * sizeof(GLfloat));
171
172         /* write span */
173         span.x = destx;
174         span.y = desty + row;
175         span.end = width;
176         span.array->ChanType = GL_FLOAT;
177         if (zoom) {
178            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
179         }
180         else {
181            _swrast_write_rgba_span(ctx, &span);
182         }
183      }
184      /* restore this */
185      span.array->ChanType = CHAN_TYPE;
186   }
187
188   free(convImage);
189}
190
191
192/**
193 * RGBA copypixels
194 */
195static void
196copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
197                 GLint width, GLint height, GLint destx, GLint desty)
198{
199   GLfloat *tmpImage, *p;
200   GLint sy, dy, stepy, row;
201   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
202   GLint overlapping;
203   GLuint transferOps = ctx->_ImageTransferState;
204   SWspan span;
205
206   if (!ctx->ReadBuffer->_ColorReadBuffer) {
207      /* no readbuffer - OK */
208      return;
209   }
210
211   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
212      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
213      return;
214   }
215   else if (ctx->Pixel.Convolution1DEnabled) {
216      /* make sure we don't apply 1D convolution */
217      transferOps &= ~(IMAGE_CONVOLUTION_BIT |
218                       IMAGE_POST_CONVOLUTION_SCALE_BIAS);
219   }
220
221   if (ctx->DrawBuffer == ctx->ReadBuffer) {
222      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
223                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
224   }
225   else {
226      overlapping = GL_FALSE;
227   }
228
229   /* Determine if copy should be done bottom-to-top or top-to-bottom */
230   if (!overlapping && srcy < desty) {
231      /* top-down  max-to-min */
232      sy = srcy + height - 1;
233      dy = desty + height - 1;
234      stepy = -1;
235   }
236   else {
237      /* bottom-up  min-to-max */
238      sy = srcy;
239      dy = desty;
240      stepy = 1;
241   }
242
243   INIT_SPAN(span, GL_BITMAP);
244   _swrast_span_default_attribs(ctx, &span);
245   span.arrayMask = SPAN_RGBA;
246   span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */
247
248   if (overlapping) {
249      tmpImage = (GLfloat *) malloc(width * height * sizeof(GLfloat) * 4);
250      if (!tmpImage) {
251         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
252         return;
253      }
254      /* read the source image as RGBA/float */
255      p = tmpImage;
256      for (row = 0; row < height; row++) {
257         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
258                                 width, srcx, sy + row, GL_FLOAT, p );
259         p += width * 4;
260      }
261      p = tmpImage;
262   }
263   else {
264      tmpImage = NULL;  /* silence compiler warnings */
265      p = NULL;
266   }
267
268   ASSERT(width < MAX_WIDTH);
269
270   for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
271      GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];
272
273      /* Get row/span of source pixels */
274      if (overlapping) {
275         /* get from buffered image */
276         memcpy(rgba, p, width * sizeof(GLfloat) * 4);
277         p += width * 4;
278      }
279      else {
280         /* get from framebuffer */
281         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
282                                 width, srcx, sy, GL_FLOAT, rgba );
283      }
284
285      if (transferOps) {
286         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
287                                       (GLfloat (*)[4]) rgba);
288      }
289
290      /* Write color span */
291      span.x = destx;
292      span.y = dy;
293      span.end = width;
294      span.array->ChanType = GL_FLOAT;
295      if (zoom) {
296         _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
297      }
298      else {
299         _swrast_write_rgba_span(ctx, &span);
300      }
301   }
302
303   span.array->ChanType = CHAN_TYPE; /* restore */
304
305   if (overlapping)
306      free(tmpImage);
307}
308
309
310/**
311 * Convert floating point Z values to integer Z values with pixel transfer's
312 * Z scale and bias.
313 */
314static void
315scale_and_bias_z(GLcontext *ctx, GLuint width,
316                 const GLfloat depth[], GLuint z[])
317{
318   const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
319   GLuint i;
320
321   if (depthMax <= 0xffffff &&
322       ctx->Pixel.DepthScale == 1.0 &&
323       ctx->Pixel.DepthBias == 0.0) {
324      /* no scale or bias and no clamping and no worry of overflow */
325      const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
326      for (i = 0; i < width; i++) {
327         z[i] = (GLuint) (depth[i] * depthMaxF);
328      }
329   }
330   else {
331      /* need to be careful with overflow */
332      const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
333      for (i = 0; i < width; i++) {
334         GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
335         d = CLAMP(d, 0.0, 1.0) * depthMaxF;
336         if (d >= depthMaxF)
337            z[i] = depthMax;
338         else
339            z[i] = (GLuint) d;
340      }
341   }
342}
343
344
345
346/*
347 * TODO: Optimize!!!!
348 */
349static void
350copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
351                   GLint width, GLint height,
352                   GLint destx, GLint desty )
353{
354   struct gl_framebuffer *fb = ctx->ReadBuffer;
355   struct gl_renderbuffer *readRb = fb->_DepthBuffer;
356   GLfloat *p, *tmpImage;
357   GLint sy, dy, stepy;
358   GLint j;
359   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
360   GLint overlapping;
361   SWspan span;
362
363   if (!readRb) {
364      /* no readbuffer - OK */
365      return;
366   }
367
368   INIT_SPAN(span, GL_BITMAP);
369   _swrast_span_default_attribs(ctx, &span);
370   span.arrayMask = SPAN_Z;
371
372   if (ctx->DrawBuffer == ctx->ReadBuffer) {
373      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
374                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
375   }
376   else {
377      overlapping = GL_FALSE;
378   }
379
380   /* Determine if copy should be bottom-to-top or top-to-bottom */
381   if (!overlapping && srcy < desty) {
382      /* top-down  max-to-min */
383      sy = srcy + height - 1;
384      dy = desty + height - 1;
385      stepy = -1;
386   }
387   else {
388      /* bottom-up  min-to-max */
389      sy = srcy;
390      dy = desty;
391      stepy = 1;
392   }
393
394   if (overlapping) {
395      GLint ssy = sy;
396      tmpImage = (GLfloat *) malloc(width * height * sizeof(GLfloat));
397      if (!tmpImage) {
398         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
399         return;
400      }
401      p = tmpImage;
402      for (j = 0; j < height; j++, ssy += stepy) {
403         _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
404         p += width;
405      }
406      p = tmpImage;
407   }
408   else {
409      tmpImage = NULL;  /* silence compiler warning */
410      p = NULL;
411   }
412
413   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
414      GLfloat depth[MAX_WIDTH];
415      /* get depth values */
416      if (overlapping) {
417         memcpy(depth, p, width * sizeof(GLfloat));
418         p += width;
419      }
420      else {
421         _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
422      }
423
424      /* apply scale and bias */
425      scale_and_bias_z(ctx, width, depth, span.array->z);
426
427      /* write depth values */
428      span.x = destx;
429      span.y = dy;
430      span.end = width;
431      if (zoom)
432         _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
433      else
434         _swrast_write_rgba_span(ctx, &span);
435   }
436
437   if (overlapping)
438      free(tmpImage);
439}
440
441
442
443static void
444copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
445                     GLint width, GLint height,
446                     GLint destx, GLint desty )
447{
448   struct gl_framebuffer *fb = ctx->ReadBuffer;
449   struct gl_renderbuffer *rb = fb->_StencilBuffer;
450   GLint sy, dy, stepy;
451   GLint j;
452   GLstencil *p, *tmpImage;
453   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
454   GLint overlapping;
455
456   if (!rb) {
457      /* no readbuffer - OK */
458      return;
459   }
460
461   if (ctx->DrawBuffer == ctx->ReadBuffer) {
462      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
463                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
464   }
465   else {
466      overlapping = GL_FALSE;
467   }
468
469   /* Determine if copy should be bottom-to-top or top-to-bottom */
470   if (!overlapping && srcy < desty) {
471      /* top-down  max-to-min */
472      sy = srcy + height - 1;
473      dy = desty + height - 1;
474      stepy = -1;
475   }
476   else {
477      /* bottom-up  min-to-max */
478      sy = srcy;
479      dy = desty;
480      stepy = 1;
481   }
482
483   if (overlapping) {
484      GLint ssy = sy;
485      tmpImage = (GLstencil *) malloc(width * height * sizeof(GLstencil));
486      if (!tmpImage) {
487         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
488         return;
489      }
490      p = tmpImage;
491      for (j = 0; j < height; j++, ssy += stepy) {
492         _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
493         p += width;
494      }
495      p = tmpImage;
496   }
497   else {
498      tmpImage = NULL;  /* silence compiler warning */
499      p = NULL;
500   }
501
502   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
503      GLstencil stencil[MAX_WIDTH];
504
505      /* Get stencil values */
506      if (overlapping) {
507         memcpy(stencil, p, width * sizeof(GLstencil));
508         p += width;
509      }
510      else {
511         _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
512      }
513
514      _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
515
516      /* Write stencil values */
517      if (zoom) {
518         _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
519                                           destx, dy, stencil);
520      }
521      else {
522         _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
523      }
524   }
525
526   if (overlapping)
527      free(tmpImage);
528}
529
530
531/**
532 * This isn't terribly efficient.  If a driver really has combined
533 * depth/stencil buffers the driver should implement an optimized
534 * CopyPixels function.
535 */
536static void
537copy_depth_stencil_pixels(GLcontext *ctx,
538                          const GLint srcX, const GLint srcY,
539                          const GLint width, const GLint height,
540                          const GLint destX, const GLint destY)
541{
542   struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
543   GLint sy, dy, stepy;
544   GLint j;
545   GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
546   GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
547   const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
548   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
549   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
550   const GLboolean scaleOrBias
551      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
552   GLint overlapping;
553
554   depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
555   depthReadRb = ctx->ReadBuffer->_DepthBuffer;
556   stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
557
558   ASSERT(depthDrawRb);
559   ASSERT(depthReadRb);
560   ASSERT(stencilReadRb);
561
562   if (ctx->DrawBuffer == ctx->ReadBuffer) {
563      overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
564                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
565   }
566   else {
567      overlapping = GL_FALSE;
568   }
569
570   /* Determine if copy should be bottom-to-top or top-to-bottom */
571   if (!overlapping && srcY < destY) {
572      /* top-down  max-to-min */
573      sy = srcY + height - 1;
574      dy = destY + height - 1;
575      stepy = -1;
576   }
577   else {
578      /* bottom-up  min-to-max */
579      sy = srcY;
580      dy = destY;
581      stepy = 1;
582   }
583
584   if (overlapping) {
585      GLint ssy = sy;
586
587      if (stencilMask != 0x0) {
588         tempStencilImage
589            = (GLstencil *) malloc(width * height * sizeof(GLstencil));
590         if (!tempStencilImage) {
591            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
592            return;
593         }
594
595         /* get copy of stencil pixels */
596         stencilPtr = tempStencilImage;
597         for (j = 0; j < height; j++, ssy += stepy) {
598            _swrast_read_stencil_span(ctx, stencilReadRb,
599                                      width, srcX, ssy, stencilPtr);
600            stencilPtr += width;
601         }
602         stencilPtr = tempStencilImage;
603      }
604
605      if (ctx->Depth.Mask) {
606         tempDepthImage
607            = (GLfloat *) malloc(width * height * sizeof(GLfloat));
608         if (!tempDepthImage) {
609            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
610            free(tempStencilImage);
611            return;
612         }
613
614         /* get copy of depth pixels */
615         depthPtr = tempDepthImage;
616         for (j = 0; j < height; j++, ssy += stepy) {
617            _swrast_read_depth_span_float(ctx, depthReadRb,
618                                          width, srcX, ssy, depthPtr);
619            depthPtr += width;
620         }
621         depthPtr = tempDepthImage;
622      }
623   }
624
625   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
626      if (stencilMask != 0x0) {
627         GLstencil stencil[MAX_WIDTH];
628
629         /* Get stencil values */
630         if (overlapping) {
631            memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
632            stencilPtr += width;
633         }
634         else {
635            _swrast_read_stencil_span(ctx, stencilReadRb,
636                                      width, srcX, sy, stencil);
637         }
638
639         _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
640
641         /* Write values */
642         if (zoom) {
643            _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
644                                              destX, dy, stencil);
645         }
646         else {
647            _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
648         }
649      }
650
651      if (ctx->Depth.Mask) {
652         GLfloat depth[MAX_WIDTH];
653         GLuint zVals32[MAX_WIDTH];
654         GLushort zVals16[MAX_WIDTH];
655         GLvoid *zVals;
656         GLuint zBytes;
657
658         /* get depth values */
659         if (overlapping) {
660            memcpy(depth, depthPtr, width * sizeof(GLfloat));
661            depthPtr += width;
662         }
663         else {
664            _swrast_read_depth_span_float(ctx, depthReadRb,
665                                          width, srcX, sy, depth);
666         }
667
668         /* scale & bias */
669         if (scaleOrBias) {
670            _mesa_scale_and_bias_depth(ctx, width, depth);
671         }
672         /* convert to integer Z values */
673         if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
674            GLint k;
675            for (k = 0; k < width; k++)
676               zVals16[k] = (GLushort) (depth[k] * depthScale);
677            zVals = zVals16;
678            zBytes = 2;
679         }
680         else {
681            GLint k;
682            for (k = 0; k < width; k++)
683               zVals32[k] = (GLuint) (depth[k] * depthScale);
684            zVals = zVals32;
685            zBytes = 4;
686         }
687
688         /* Write values */
689         if (zoom) {
690            _swrast_write_zoomed_z_span(ctx, destX, destY, width,
691                                        destX, dy, zVals);
692         }
693         else {
694            _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
695         }
696      }
697   }
698
699   if (tempStencilImage)
700      free(tempStencilImage);
701
702   if (tempDepthImage)
703      free(tempDepthImage);
704}
705
706
707
708/**
709 * Try to do a fast copy pixels.
710 */
711static GLboolean
712fast_copy_pixels(GLcontext *ctx,
713                 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
714                 GLint dstX, GLint dstY, GLenum type)
715{
716   struct gl_framebuffer *srcFb = ctx->ReadBuffer;
717   struct gl_framebuffer *dstFb = ctx->DrawBuffer;
718   struct gl_renderbuffer *srcRb, *dstRb;
719   GLint row, yStep;
720
721   if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
722       ctx->Pixel.ZoomX != 1.0F ||
723       ctx->Pixel.ZoomY != 1.0F ||
724       ctx->_ImageTransferState) {
725      /* can't handle these */
726      return GL_FALSE;
727   }
728
729   if (type == GL_COLOR) {
730      if (dstFb->_NumColorDrawBuffers != 1)
731         return GL_FALSE;
732      srcRb = srcFb->_ColorReadBuffer;
733      dstRb = dstFb->_ColorDrawBuffers[0];
734   }
735   else if (type == GL_STENCIL) {
736      srcRb = srcFb->_StencilBuffer;
737      dstRb = dstFb->_StencilBuffer;
738   }
739   else if (type == GL_DEPTH) {
740      srcRb = srcFb->_DepthBuffer;
741      dstRb = dstFb->_DepthBuffer;
742   }
743   else {
744      ASSERT(type == GL_DEPTH_STENCIL_EXT);
745      /* XXX correct? */
746      srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
747      dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
748   }
749
750   /* src and dst renderbuffers must be same format and type */
751   if (!srcRb || !dstRb ||
752       srcRb->DataType != dstRb->DataType ||
753       srcRb->_BaseFormat != dstRb->_BaseFormat) {
754      return GL_FALSE;
755   }
756
757   /* clipping not supported */
758   if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
759       srcY < 0 || srcY + height > (GLint) srcFb->Height ||
760       dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
761       dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
762      return GL_FALSE;
763   }
764
765   /* overlapping src/dst doesn't matter, just determine Y direction */
766   if (srcY < dstY) {
767      /* top-down  max-to-min */
768      srcY = srcY + height - 1;
769      dstY = dstY + height - 1;
770      yStep = -1;
771   }
772   else {
773      /* bottom-up  min-to-max */
774      yStep = 1;
775   }
776
777   for (row = 0; row < height; row++) {
778      GLuint temp[MAX_WIDTH][4];
779      srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
780      dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
781      srcY += yStep;
782      dstY += yStep;
783   }
784
785   return GL_TRUE;
786}
787
788
789/**
790 * Do software-based glCopyPixels.
791 * By time we get here, all parameters will have been error-checked.
792 */
793void
794_swrast_CopyPixels( GLcontext *ctx,
795		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
796		    GLint destx, GLint desty, GLenum type )
797{
798   SWcontext *swrast = SWRAST_CONTEXT(ctx);
799   swrast_render_start(ctx);
800
801   if (!_mesa_check_conditional_render(ctx))
802      return; /* don't copy */
803
804   if (swrast->NewState)
805      _swrast_validate_derived( ctx );
806
807   if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
808      switch (type) {
809      case GL_COLOR:
810         copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
811         break;
812      case GL_DEPTH:
813         copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
814         break;
815      case GL_STENCIL:
816         copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
817         break;
818      case GL_DEPTH_STENCIL_EXT:
819         copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
820         break;
821      default:
822         _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
823      }
824   }
825
826   swrast_render_finish(ctx);
827}
828