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