OSDN Git Service

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