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