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