OSDN Git Service

5ecfb1e90a97bd0116855c7653dc5b938f982e97
[android-x86/external-mesa.git] / src / mesa / swrast / s_copypix.c
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  */
51 static GLboolean
52 regions_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  */
100 static void
101 copy_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  */
196 static void
197 copy_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
311 static void
312 copy_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  */
409 static void
410 scale_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  */
444 static void
445 copy_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
546 static void
547 copy_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  */
639 static void
640 copy_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  */
814 static GLboolean
815 fast_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  */
896 void
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    swrast_render_start(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    swrast_render_finish(ctx);
932 }