s_copypix.c revision 171dcdfa27dda30916a7f9bfed89577feee5d350
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         GLvoid *rgba = (GLvoid *) 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   SWcontext *swrast = SWRAST_CONTEXT(ctx);
192   const GLbitfield prevActiveAttribs = swrast->_ActiveAttribMask;
193   GLfloat *tmpImage, *p;
194   GLint sy, dy, stepy, row;
195   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
196   GLint overlapping;
197   GLuint transferOps = ctx->_ImageTransferState;
198   SWspan span;
199
200   if (!ctx->ReadBuffer->_ColorReadBuffer) {
201      /* no readbuffer - OK */
202      goto end;
203   }
204
205   /* don't interpolate COL0 and overwrite the glDrawPixel colors! */
206   swrast->_ActiveAttribMask &= ~FRAG_BIT_COL0;
207
208   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
209      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
210      goto end;
211   }
212   else if (ctx->Pixel.Convolution1DEnabled) {
213      /* make sure we don't apply 1D convolution */
214      transferOps &= ~(IMAGE_CONVOLUTION_BIT |
215                       IMAGE_POST_CONVOLUTION_SCALE_BIAS);
216   }
217
218   if (ctx->DrawBuffer == ctx->ReadBuffer) {
219      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
220                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
221   }
222   else {
223      overlapping = GL_FALSE;
224   }
225
226   /* Determine if copy should be done bottom-to-top or top-to-bottom */
227   if (!overlapping && srcy < desty) {
228      /* top-down  max-to-min */
229      sy = srcy + height - 1;
230      dy = desty + height - 1;
231      stepy = -1;
232   }
233   else {
234      /* bottom-up  min-to-max */
235      sy = srcy;
236      dy = desty;
237      stepy = 1;
238   }
239
240   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
241   _swrast_span_default_attribs(ctx, &span);
242
243   if (overlapping) {
244      tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4);
245      if (!tmpImage) {
246         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
247         goto end;
248      }
249      /* read the source image as RGBA/float */
250      p = tmpImage;
251      for (row = 0; row < height; row++) {
252         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
253                                 width, srcx, sy + row, GL_FLOAT, p );
254         p += width * 4;
255      }
256      p = tmpImage;
257   }
258   else {
259      tmpImage = NULL;  /* silence compiler warnings */
260      p = NULL;
261   }
262
263   ASSERT(width < MAX_WIDTH);
264
265   for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
266      GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];
267
268      /* Get row/span of source pixels */
269      if (overlapping) {
270         /* get from buffered image */
271         _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4);
272         p += width * 4;
273      }
274      else {
275         /* get from framebuffer */
276         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
277                                 width, srcx, sy, GL_FLOAT, rgba );
278      }
279
280      if (transferOps) {
281         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
282                                       (GLfloat (*)[4]) rgba);
283      }
284
285      /* Write color span */
286      span.x = destx;
287      span.y = dy;
288      span.end = width;
289      span.array->ChanType = GL_FLOAT;
290      if (zoom) {
291         _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
292      }
293      else {
294         _swrast_write_rgba_span(ctx, &span);
295      }
296   }
297
298   span.array->ChanType = CHAN_TYPE; /* restore */
299
300   if (overlapping)
301      _mesa_free(tmpImage);
302
303end:
304   swrast->_ActiveAttribMask = prevActiveAttribs;
305}
306
307
308static void
309copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
310                GLint width, GLint height,
311                GLint destx, GLint desty )
312{
313   GLuint *tmpImage,*p;
314   GLint sy, dy, stepy;
315   GLint j;
316   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
317   GLint overlapping;
318   SWspan span;
319
320   if (!ctx->ReadBuffer->_ColorReadBuffer) {
321      /* no readbuffer - OK */
322      return;
323   }
324
325   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
326   _swrast_span_default_attribs(ctx, &span);
327
328   if (ctx->DrawBuffer == ctx->ReadBuffer) {
329      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
330                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
331   }
332   else {
333      overlapping = GL_FALSE;
334   }
335
336   /* Determine if copy should be bottom-to-top or top-to-bottom */
337   if (!overlapping && srcy < desty) {
338      /* top-down  max-to-min */
339      sy = srcy + height - 1;
340      dy = desty + height - 1;
341      stepy = -1;
342   }
343   else {
344      /* bottom-up  min-to-max */
345      sy = srcy;
346      dy = desty;
347      stepy = 1;
348   }
349
350   if (overlapping) {
351      GLint ssy = sy;
352      tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
353      if (!tmpImage) {
354         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
355         return;
356      }
357      /* read the image */
358      p = tmpImage;
359      for (j = 0; j < height; j++, ssy += stepy) {
360         _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
361                                  width, srcx, ssy, p );
362         p += width;
363      }
364      p = tmpImage;
365   }
366   else {
367      tmpImage = NULL;  /* silence compiler warning */
368      p = NULL;
369   }
370
371   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
372      /* Get color indexes */
373      if (overlapping) {
374         _mesa_memcpy(span.array->index, p, width * sizeof(GLuint));
375         p += width;
376      }
377      else {
378         _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
379                                  width, srcx, sy, span.array->index );
380      }
381
382      if (ctx->_ImageTransferState)
383         _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState,
384                                     width, span.array->index);
385
386      /* write color indexes */
387      span.x = destx;
388      span.y = dy;
389      span.end = width;
390      if (zoom)
391         _swrast_write_zoomed_index_span(ctx, destx, desty, &span);
392      else
393         _swrast_write_index_span(ctx, &span);
394   }
395
396   if (overlapping)
397      _mesa_free(tmpImage);
398}
399
400
401/**
402 * Convert floating point Z values to integer Z values with pixel transfer's
403 * Z scale and bias.
404 */
405static void
406scale_and_bias_z(GLcontext *ctx, GLuint width,
407                 const GLfloat depth[], GLuint z[])
408{
409   const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
410   GLuint i;
411
412   if (depthMax <= 0xffffff &&
413       ctx->Pixel.DepthScale == 1.0 &&
414       ctx->Pixel.DepthBias == 0.0) {
415      /* no scale or bias and no clamping and no worry of overflow */
416      const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
417      for (i = 0; i < width; i++) {
418         z[i] = (GLuint) (depth[i] * depthMaxF);
419      }
420   }
421   else {
422      /* need to be careful with overflow */
423      const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
424      for (i = 0; i < width; i++) {
425         GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
426         d = CLAMP(d, 0.0, 1.0) * depthMaxF;
427         if (d >= depthMaxF)
428            z[i] = depthMax;
429         else
430            z[i] = (GLuint) d;
431      }
432   }
433}
434
435
436
437/*
438 * TODO: Optimize!!!!
439 */
440static void
441copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
442                   GLint width, GLint height,
443                   GLint destx, GLint desty )
444{
445   struct gl_framebuffer *fb = ctx->ReadBuffer;
446   struct gl_renderbuffer *readRb = fb->_DepthBuffer;
447   GLfloat *p, *tmpImage;
448   GLint sy, dy, stepy;
449   GLint j;
450   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
451   GLint overlapping;
452   SWspan span;
453
454   if (!readRb) {
455      /* no readbuffer - OK */
456      return;
457   }
458
459   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
460   _swrast_span_default_attribs(ctx, &span);
461
462   if (ctx->DrawBuffer == ctx->ReadBuffer) {
463      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
464                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
465   }
466   else {
467      overlapping = GL_FALSE;
468   }
469
470   /* Determine if copy should be bottom-to-top or top-to-bottom */
471   if (!overlapping && srcy < desty) {
472      /* top-down  max-to-min */
473      sy = srcy + height - 1;
474      dy = desty + height - 1;
475      stepy = -1;
476   }
477   else {
478      /* bottom-up  min-to-max */
479      sy = srcy;
480      dy = desty;
481      stepy = 1;
482   }
483
484   if (overlapping) {
485      GLint ssy = sy;
486      tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
487      if (!tmpImage) {
488         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
489         return;
490      }
491      p = tmpImage;
492      for (j = 0; j < height; j++, ssy += stepy) {
493         _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
494         p += width;
495      }
496      p = tmpImage;
497   }
498   else {
499      tmpImage = NULL;  /* silence compiler warning */
500      p = NULL;
501   }
502
503   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
504      GLfloat depth[MAX_WIDTH];
505      /* get depth values */
506      if (overlapping) {
507         _mesa_memcpy(depth, p, width * sizeof(GLfloat));
508         p += width;
509      }
510      else {
511         _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
512      }
513
514      /* apply scale and bias */
515      scale_and_bias_z(ctx, width, depth, span.array->z);
516
517      /* write depth values */
518      span.x = destx;
519      span.y = dy;
520      span.end = width;
521      if (fb->Visual.rgbMode) {
522         if (zoom)
523            _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
524         else
525            _swrast_write_rgba_span(ctx, &span);
526      }
527      else {
528         if (zoom)
529            _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
530         else
531            _swrast_write_index_span(ctx, &span);
532      }
533   }
534
535   if (overlapping)
536      _mesa_free(tmpImage);
537}
538
539
540
541static void
542copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
543                     GLint width, GLint height,
544                     GLint destx, GLint desty )
545{
546   struct gl_framebuffer *fb = ctx->ReadBuffer;
547   struct gl_renderbuffer *rb = fb->_StencilBuffer;
548   GLint sy, dy, stepy;
549   GLint j;
550   GLstencil *p, *tmpImage;
551   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
552   GLint overlapping;
553
554   if (!rb) {
555      /* no readbuffer - OK */
556      return;
557   }
558
559   if (ctx->DrawBuffer == ctx->ReadBuffer) {
560      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
561                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
562   }
563   else {
564      overlapping = GL_FALSE;
565   }
566
567   /* Determine if copy should be bottom-to-top or top-to-bottom */
568   if (!overlapping && srcy < desty) {
569      /* top-down  max-to-min */
570      sy = srcy + height - 1;
571      dy = desty + height - 1;
572      stepy = -1;
573   }
574   else {
575      /* bottom-up  min-to-max */
576      sy = srcy;
577      dy = desty;
578      stepy = 1;
579   }
580
581   if (overlapping) {
582      GLint ssy = sy;
583      tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
584      if (!tmpImage) {
585         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
586         return;
587      }
588      p = tmpImage;
589      for (j = 0; j < height; j++, ssy += stepy) {
590         _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
591         p += width;
592      }
593      p = tmpImage;
594   }
595   else {
596      tmpImage = NULL;  /* silence compiler warning */
597      p = NULL;
598   }
599
600   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
601      GLstencil stencil[MAX_WIDTH];
602
603      /* Get stencil values */
604      if (overlapping) {
605         _mesa_memcpy(stencil, p, width * sizeof(GLstencil));
606         p += width;
607      }
608      else {
609         _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
610      }
611
612      _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
613
614      /* Write stencil values */
615      if (zoom) {
616         _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
617                                           destx, dy, stencil);
618      }
619      else {
620         _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
621      }
622   }
623
624   if (overlapping)
625      _mesa_free(tmpImage);
626}
627
628
629/**
630 * This isn't terribly efficient.  If a driver really has combined
631 * depth/stencil buffers the driver should implement an optimized
632 * CopyPixels function.
633 */
634static void
635copy_depth_stencil_pixels(GLcontext *ctx,
636                          const GLint srcX, const GLint srcY,
637                          const GLint width, const GLint height,
638                          const GLint destX, const GLint destY)
639{
640   struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
641   GLint sy, dy, stepy;
642   GLint j;
643   GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
644   GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
645   const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
646   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
647   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
648   const GLboolean scaleOrBias
649      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
650   GLint overlapping;
651
652   depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
653   depthReadRb = ctx->ReadBuffer->_DepthBuffer;
654   stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
655
656   ASSERT(depthDrawRb);
657   ASSERT(depthReadRb);
658   ASSERT(stencilReadRb);
659
660   if (ctx->DrawBuffer == ctx->ReadBuffer) {
661      overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
662                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
663   }
664   else {
665      overlapping = GL_FALSE;
666   }
667
668   /* Determine if copy should be bottom-to-top or top-to-bottom */
669   if (!overlapping && srcY < destY) {
670      /* top-down  max-to-min */
671      sy = srcY + height - 1;
672      dy = destY + height - 1;
673      stepy = -1;
674   }
675   else {
676      /* bottom-up  min-to-max */
677      sy = srcY;
678      dy = destY;
679      stepy = 1;
680   }
681
682   if (overlapping) {
683      GLint ssy = sy;
684
685      if (stencilMask != 0x0) {
686         tempStencilImage
687            = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
688         if (!tempStencilImage) {
689            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
690            return;
691         }
692
693         /* get copy of stencil pixels */
694         stencilPtr = tempStencilImage;
695         for (j = 0; j < height; j++, ssy += stepy) {
696            _swrast_read_stencil_span(ctx, stencilReadRb,
697                                      width, srcX, ssy, stencilPtr);
698            stencilPtr += width;
699         }
700         stencilPtr = tempStencilImage;
701      }
702
703      if (ctx->Depth.Mask) {
704         tempDepthImage
705            = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
706         if (!tempDepthImage) {
707            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
708            _mesa_free(tempStencilImage);
709            return;
710         }
711
712         /* get copy of depth pixels */
713         depthPtr = tempDepthImage;
714         for (j = 0; j < height; j++, ssy += stepy) {
715            _swrast_read_depth_span_float(ctx, depthReadRb,
716                                          width, srcX, ssy, depthPtr);
717            depthPtr += width;
718         }
719         depthPtr = tempDepthImage;
720      }
721   }
722
723   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
724      if (stencilMask != 0x0) {
725         GLstencil stencil[MAX_WIDTH];
726
727         /* Get stencil values */
728         if (overlapping) {
729            _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
730            stencilPtr += width;
731         }
732         else {
733            _swrast_read_stencil_span(ctx, stencilReadRb,
734                                      width, srcX, sy, stencil);
735         }
736
737         _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
738
739         /* Write values */
740         if (zoom) {
741            _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
742                                              destX, dy, stencil);
743         }
744         else {
745            _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
746         }
747      }
748
749      if (ctx->Depth.Mask) {
750         GLfloat depth[MAX_WIDTH];
751         GLuint zVals32[MAX_WIDTH];
752         GLushort zVals16[MAX_WIDTH];
753         GLvoid *zVals;
754         GLuint zBytes;
755
756         /* get depth values */
757         if (overlapping) {
758            _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat));
759            depthPtr += width;
760         }
761         else {
762            _swrast_read_depth_span_float(ctx, depthReadRb,
763                                          width, srcX, sy, depth);
764         }
765
766         /* scale & bias */
767         if (scaleOrBias) {
768            _mesa_scale_and_bias_depth(ctx, width, depth);
769         }
770         /* convert to integer Z values */
771         if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
772            GLint k;
773            for (k = 0; k < width; k++)
774               zVals16[k] = (GLushort) (depth[k] * depthScale);
775            zVals = zVals16;
776            zBytes = 2;
777         }
778         else {
779            GLint k;
780            for (k = 0; k < width; k++)
781               zVals32[k] = (GLuint) (depth[k] * depthScale);
782            zVals = zVals32;
783            zBytes = 4;
784         }
785
786         /* Write values */
787         if (zoom) {
788            _swrast_write_zoomed_z_span(ctx, destX, destY, width,
789                                        destX, dy, zVals);
790         }
791         else {
792            _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
793         }
794      }
795   }
796
797   if (tempStencilImage)
798      _mesa_free(tempStencilImage);
799
800   if (tempDepthImage)
801      _mesa_free(tempDepthImage);
802}
803
804
805
806/**
807 * Try to do a fast copy pixels.
808 */
809static GLboolean
810fast_copy_pixels(GLcontext *ctx,
811                 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
812                 GLint dstX, GLint dstY, GLenum type)
813{
814   struct gl_framebuffer *srcFb = ctx->ReadBuffer;
815   struct gl_framebuffer *dstFb = ctx->DrawBuffer;
816   struct gl_renderbuffer *srcRb, *dstRb;
817   GLint row, yStep;
818
819   if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
820       ctx->Pixel.ZoomX != 1.0F ||
821       ctx->Pixel.ZoomY != 1.0F ||
822       ctx->_ImageTransferState) {
823      /* can't handle these */
824      return GL_FALSE;
825   }
826
827   if (type == GL_COLOR) {
828      if (dstFb->_NumColorDrawBuffers[0] != 1)
829         return GL_FALSE;
830      srcRb = srcFb->_ColorReadBuffer;
831      dstRb = dstFb->_ColorDrawBuffers[0][0];
832   }
833   else if (type == GL_STENCIL) {
834      srcRb = srcFb->_StencilBuffer;
835      dstRb = dstFb->_StencilBuffer;
836   }
837   else if (type == GL_DEPTH) {
838      srcRb = srcFb->_DepthBuffer;
839      dstRb = dstFb->_DepthBuffer;
840   }
841   else {
842      ASSERT(type == GL_DEPTH_STENCIL_EXT);
843      /* XXX correct? */
844      srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
845      dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
846   }
847
848   /* src and dst renderbuffers must be same format and type */
849   if (!srcRb || !dstRb ||
850       srcRb->DataType != dstRb->DataType ||
851       srcRb->_BaseFormat != dstRb->_BaseFormat) {
852      return GL_FALSE;
853   }
854
855   /* clipping not supported */
856   if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
857       srcY < 0 || srcY + height > (GLint) srcFb->Height ||
858       dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
859       dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
860      return GL_FALSE;
861   }
862
863   /* overlapping src/dst doesn't matter, just determine Y direction */
864   if (srcY < dstY) {
865      /* top-down  max-to-min */
866      srcY = srcY + height - 1;
867      dstY = dstY + height - 1;
868      yStep = -1;
869   }
870   else {
871      /* bottom-up  min-to-max */
872      yStep = 1;
873   }
874
875   for (row = 0; row < height; row++) {
876      GLuint temp[MAX_WIDTH][4];
877      srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
878      dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
879      srcY += yStep;
880      dstY += yStep;
881   }
882
883   return GL_TRUE;
884}
885
886
887/**
888 * Do software-based glCopyPixels.
889 * By time we get here, all parameters will have been error-checked.
890 */
891void
892_swrast_CopyPixels( GLcontext *ctx,
893		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
894		    GLint destx, GLint desty, GLenum type )
895{
896   SWcontext *swrast = SWRAST_CONTEXT(ctx);
897   RENDER_START(swrast,ctx);
898
899   if (swrast->NewState)
900      _swrast_validate_derived( ctx );
901
902   if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
903      switch (type) {
904      case GL_COLOR:
905         if (ctx->Visual.rgbMode) {
906            copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
907         }
908         else {
909            copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
910         }
911         break;
912      case GL_DEPTH:
913         copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
914         break;
915      case GL_STENCIL:
916         copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
917         break;
918      case GL_DEPTH_STENCIL_EXT:
919         copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
920         break;
921      default:
922         _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
923      }
924   }
925
926   RENDER_FINISH(swrast,ctx);
927}
928