Merge branch 'origin' into i915-unification
[mesa.git] / src / mesa / swrast / s_copypix.c
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 */
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 + (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 */
93 static void
94 copy_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 */
187 static void
188 copy_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
303 end:
304 swrast->_ActiveAttribMask = prevActiveAttribs;
305 }
306
307
308 static void
309 copy_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 */
405 static void
406 scale_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 */
440 static void
441 copy_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
541 static void
542 copy_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 */
634 static void
635 copy_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 */
809 static GLboolean
810 fast_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 */
891 void
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 }