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