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