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