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