simplify INIT_SPAN code
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "glheader.h"
27 #include "context.h"
28 #include "colormac.h"
29 #include "convolve.h"
30 #include "histogram.h"
31 #include "image.h"
32 #include "macros.h"
33 #include "imports.h"
34 #include "pixel.h"
35
36 #include "s_context.h"
37 #include "s_depth.h"
38 #include "s_span.h"
39 #include "s_stencil.h"
40 #include "s_zoom.h"
41
42
43
44 /**
45 * Determine if there's overlap in an image copy.
46 * This test also compensates for the fact that copies are done from
47 * bottom to top and overlaps can sometimes be handled correctly
48 * without making a temporary image copy.
49 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
50 */
51 static GLboolean
52 regions_overlap(GLint srcx, GLint srcy,
53 GLint dstx, GLint dsty,
54 GLint width, GLint height,
55 GLfloat zoomX, GLfloat zoomY)
56 {
57 if (zoomX == 1.0 && zoomY == 1.0) {
58 /* no zoom */
59 if (srcx >= dstx + width || (srcx + width <= dstx)) {
60 return GL_FALSE;
61 }
62 else if (srcy < dsty) { /* this is OK */
63 return GL_FALSE;
64 }
65 else if (srcy > dsty + height) {
66 return GL_FALSE;
67 }
68 else {
69 return GL_TRUE;
70 }
71 }
72 else {
73 /* add one pixel of slop when zooming, just to be safe */
74 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
75 return GL_FALSE;
76 }
77 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
78 return GL_FALSE;
79 }
80 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
81 return GL_FALSE;
82 }
83 else {
84 return GL_TRUE;
85 }
86 }
87 }
88
89
90 /**
91 * RGBA copypixels with convolution.
92 */
93 static void
94 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
95 GLint width, GLint height, GLint destx, GLint desty)
96 {
97 GLint row;
98 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
99 const GLbitfield transferOps = ctx->_ImageTransferState;
100 const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
101 || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
102 GLfloat *dest, *tmpImage, *convImage;
103 SWspan span;
104
105 INIT_SPAN(span, GL_BITMAP);
106 _swrast_span_default_attribs(ctx, &span);
107 span.arrayMask = SPAN_RGBA;
108 span.arrayAttribs = FRAG_BIT_COL0;
109
110 /* allocate space for GLfloat image */
111 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
112 if (!tmpImage) {
113 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
114 return;
115 }
116 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
117 if (!convImage) {
118 _mesa_free(tmpImage);
119 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
120 return;
121 }
122
123 /* read source image as float/RGBA */
124 dest = tmpImage;
125 for (row = 0; row < height; row++) {
126 _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
127 width, srcx, srcy + row, GL_FLOAT, dest);
128 dest += 4 * width;
129 }
130
131 /* do the image transfer ops which preceed convolution */
132 for (row = 0; row < height; row++) {
133 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
134 _mesa_apply_rgba_transfer_ops(ctx,
135 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
136 width, rgba);
137 }
138
139 /* do convolution */
140 if (ctx->Pixel.Convolution2DEnabled) {
141 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
142 }
143 else {
144 ASSERT(ctx->Pixel.Separable2DEnabled);
145 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
146 }
147 _mesa_free(tmpImage);
148
149 /* do remaining post-convolution image transfer ops */
150 for (row = 0; row < height; row++) {
151 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
152 _mesa_apply_rgba_transfer_ops(ctx,
153 transferOps & IMAGE_POST_CONVOLUTION_BITS,
154 width, rgba);
155 }
156
157 if (!sink) {
158 /* write the new image */
159 for (row = 0; row < height; row++) {
160 const GLfloat *src = convImage + row * width * 4;
161 GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
162
163 /* copy convolved colors into span array */
164 _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat));
165
166 /* write span */
167 span.x = destx;
168 span.y = desty + row;
169 span.end = width;
170 span.array->ChanType = GL_FLOAT;
171 if (zoom) {
172 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
173 }
174 else {
175 _swrast_write_rgba_span(ctx, &span);
176 }
177 }
178 /* restore this */
179 span.array->ChanType = CHAN_TYPE;
180 }
181
182 _mesa_free(convImage);
183 }
184
185
186 /**
187 * RGBA copypixels
188 */
189 static void
190 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
191 GLint width, GLint height, GLint destx, GLint desty)
192 {
193 GLfloat *tmpImage, *p;
194 GLint sy, dy, stepy, row;
195 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
196 GLint overlapping;
197 GLuint transferOps = ctx->_ImageTransferState;
198 SWspan span;
199
200 if (!ctx->ReadBuffer->_ColorReadBuffer) {
201 /* no readbuffer - OK */
202 return;
203 }
204
205 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
206 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
207 return;
208 }
209 else if (ctx->Pixel.Convolution1DEnabled) {
210 /* make sure we don't apply 1D convolution */
211 transferOps &= ~(IMAGE_CONVOLUTION_BIT |
212 IMAGE_POST_CONVOLUTION_SCALE_BIAS);
213 }
214
215 if (ctx->DrawBuffer == ctx->ReadBuffer) {
216 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
217 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
218 }
219 else {
220 overlapping = GL_FALSE;
221 }
222
223 /* Determine if copy should be done bottom-to-top or top-to-bottom */
224 if (!overlapping && srcy < desty) {
225 /* top-down max-to-min */
226 sy = srcy + height - 1;
227 dy = desty + height - 1;
228 stepy = -1;
229 }
230 else {
231 /* bottom-up min-to-max */
232 sy = srcy;
233 dy = desty;
234 stepy = 1;
235 }
236
237 INIT_SPAN(span, GL_BITMAP);
238 _swrast_span_default_attribs(ctx, &span);
239 span.arrayMask = SPAN_RGBA;
240 span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */
241
242 if (overlapping) {
243 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4);
244 if (!tmpImage) {
245 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
246 return;
247 }
248 /* read the source image as RGBA/float */
249 p = tmpImage;
250 for (row = 0; row < height; row++) {
251 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
252 width, srcx, sy + row, GL_FLOAT, p );
253 p += width * 4;
254 }
255 p = tmpImage;
256 }
257 else {
258 tmpImage = NULL; /* silence compiler warnings */
259 p = NULL;
260 }
261
262 ASSERT(width < MAX_WIDTH);
263
264 for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
265 GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];
266
267 /* Get row/span of source pixels */
268 if (overlapping) {
269 /* get from buffered image */
270 _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4);
271 p += width * 4;
272 }
273 else {
274 /* get from framebuffer */
275 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
276 width, srcx, sy, GL_FLOAT, rgba );
277 }
278
279 if (transferOps) {
280 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
281 (GLfloat (*)[4]) rgba);
282 }
283
284 /* Write color span */
285 span.x = destx;
286 span.y = dy;
287 span.end = width;
288 span.array->ChanType = GL_FLOAT;
289 if (zoom) {
290 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
291 }
292 else {
293 _swrast_write_rgba_span(ctx, &span);
294 }
295 }
296
297 span.array->ChanType = CHAN_TYPE; /* restore */
298
299 if (overlapping)
300 _mesa_free(tmpImage);
301 }
302
303
304 static void
305 copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
306 GLint width, GLint height,
307 GLint destx, GLint desty )
308 {
309 GLuint *tmpImage,*p;
310 GLint sy, dy, stepy;
311 GLint j;
312 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
313 GLint overlapping;
314 SWspan span;
315
316 if (!ctx->ReadBuffer->_ColorReadBuffer) {
317 /* no readbuffer - OK */
318 return;
319 }
320
321 INIT_SPAN(span, GL_BITMAP);
322 _swrast_span_default_attribs(ctx, &span);
323 span.arrayMask = SPAN_INDEX;
324
325 if (ctx->DrawBuffer == ctx->ReadBuffer) {
326 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
327 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
328 }
329 else {
330 overlapping = GL_FALSE;
331 }
332
333 /* Determine if copy should be bottom-to-top or top-to-bottom */
334 if (!overlapping && srcy < desty) {
335 /* top-down max-to-min */
336 sy = srcy + height - 1;
337 dy = desty + height - 1;
338 stepy = -1;
339 }
340 else {
341 /* bottom-up min-to-max */
342 sy = srcy;
343 dy = desty;
344 stepy = 1;
345 }
346
347 if (overlapping) {
348 GLint ssy = sy;
349 tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
350 if (!tmpImage) {
351 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
352 return;
353 }
354 /* read the image */
355 p = tmpImage;
356 for (j = 0; j < height; j++, ssy += stepy) {
357 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
358 width, srcx, ssy, p );
359 p += width;
360 }
361 p = tmpImage;
362 }
363 else {
364 tmpImage = NULL; /* silence compiler warning */
365 p = NULL;
366 }
367
368 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
369 /* Get color indexes */
370 if (overlapping) {
371 _mesa_memcpy(span.array->index, p, width * sizeof(GLuint));
372 p += width;
373 }
374 else {
375 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
376 width, srcx, sy, span.array->index );
377 }
378
379 if (ctx->_ImageTransferState)
380 _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState,
381 width, span.array->index);
382
383 /* write color indexes */
384 span.x = destx;
385 span.y = dy;
386 span.end = width;
387 if (zoom)
388 _swrast_write_zoomed_index_span(ctx, destx, desty, &span);
389 else
390 _swrast_write_index_span(ctx, &span);
391 }
392
393 if (overlapping)
394 _mesa_free(tmpImage);
395 }
396
397
398 /**
399 * Convert floating point Z values to integer Z values with pixel transfer's
400 * Z scale and bias.
401 */
402 static void
403 scale_and_bias_z(GLcontext *ctx, GLuint width,
404 const GLfloat depth[], GLuint z[])
405 {
406 const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
407 GLuint i;
408
409 if (depthMax <= 0xffffff &&
410 ctx->Pixel.DepthScale == 1.0 &&
411 ctx->Pixel.DepthBias == 0.0) {
412 /* no scale or bias and no clamping and no worry of overflow */
413 const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
414 for (i = 0; i < width; i++) {
415 z[i] = (GLuint) (depth[i] * depthMaxF);
416 }
417 }
418 else {
419 /* need to be careful with overflow */
420 const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
421 for (i = 0; i < width; i++) {
422 GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
423 d = CLAMP(d, 0.0, 1.0) * depthMaxF;
424 if (d >= depthMaxF)
425 z[i] = depthMax;
426 else
427 z[i] = (GLuint) d;
428 }
429 }
430 }
431
432
433
434 /*
435 * TODO: Optimize!!!!
436 */
437 static void
438 copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
439 GLint width, GLint height,
440 GLint destx, GLint desty )
441 {
442 struct gl_framebuffer *fb = ctx->ReadBuffer;
443 struct gl_renderbuffer *readRb = fb->_DepthBuffer;
444 GLfloat *p, *tmpImage;
445 GLint sy, dy, stepy;
446 GLint j;
447 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
448 GLint overlapping;
449 SWspan span;
450
451 if (!readRb) {
452 /* no readbuffer - OK */
453 return;
454 }
455
456 INIT_SPAN(span, GL_BITMAP);
457 _swrast_span_default_attribs(ctx, &span);
458 span.arrayMask = SPAN_Z;
459
460 if (ctx->DrawBuffer == ctx->ReadBuffer) {
461 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
462 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
463 }
464 else {
465 overlapping = GL_FALSE;
466 }
467
468 /* Determine if copy should be bottom-to-top or top-to-bottom */
469 if (!overlapping && srcy < desty) {
470 /* top-down max-to-min */
471 sy = srcy + height - 1;
472 dy = desty + height - 1;
473 stepy = -1;
474 }
475 else {
476 /* bottom-up min-to-max */
477 sy = srcy;
478 dy = desty;
479 stepy = 1;
480 }
481
482 if (overlapping) {
483 GLint ssy = sy;
484 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
485 if (!tmpImage) {
486 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
487 return;
488 }
489 p = tmpImage;
490 for (j = 0; j < height; j++, ssy += stepy) {
491 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
492 p += width;
493 }
494 p = tmpImage;
495 }
496 else {
497 tmpImage = NULL; /* silence compiler warning */
498 p = NULL;
499 }
500
501 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
502 GLfloat depth[MAX_WIDTH];
503 /* get depth values */
504 if (overlapping) {
505 _mesa_memcpy(depth, p, width * sizeof(GLfloat));
506 p += width;
507 }
508 else {
509 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
510 }
511
512 /* apply scale and bias */
513 scale_and_bias_z(ctx, width, depth, span.array->z);
514
515 /* write depth values */
516 span.x = destx;
517 span.y = dy;
518 span.end = width;
519 if (fb->Visual.rgbMode) {
520 if (zoom)
521 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
522 else
523 _swrast_write_rgba_span(ctx, &span);
524 }
525 else {
526 if (zoom)
527 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
528 else
529 _swrast_write_index_span(ctx, &span);
530 }
531 }
532
533 if (overlapping)
534 _mesa_free(tmpImage);
535 }
536
537
538
539 static void
540 copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
541 GLint width, GLint height,
542 GLint destx, GLint desty )
543 {
544 struct gl_framebuffer *fb = ctx->ReadBuffer;
545 struct gl_renderbuffer *rb = fb->_StencilBuffer;
546 GLint sy, dy, stepy;
547 GLint j;
548 GLstencil *p, *tmpImage;
549 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
550 GLint overlapping;
551
552 if (!rb) {
553 /* no readbuffer - OK */
554 return;
555 }
556
557 if (ctx->DrawBuffer == ctx->ReadBuffer) {
558 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
559 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
560 }
561 else {
562 overlapping = GL_FALSE;
563 }
564
565 /* Determine if copy should be bottom-to-top or top-to-bottom */
566 if (!overlapping && srcy < desty) {
567 /* top-down max-to-min */
568 sy = srcy + height - 1;
569 dy = desty + height - 1;
570 stepy = -1;
571 }
572 else {
573 /* bottom-up min-to-max */
574 sy = srcy;
575 dy = desty;
576 stepy = 1;
577 }
578
579 if (overlapping) {
580 GLint ssy = sy;
581 tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
582 if (!tmpImage) {
583 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
584 return;
585 }
586 p = tmpImage;
587 for (j = 0; j < height; j++, ssy += stepy) {
588 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
589 p += width;
590 }
591 p = tmpImage;
592 }
593 else {
594 tmpImage = NULL; /* silence compiler warning */
595 p = NULL;
596 }
597
598 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
599 GLstencil stencil[MAX_WIDTH];
600
601 /* Get stencil values */
602 if (overlapping) {
603 _mesa_memcpy(stencil, p, width * sizeof(GLstencil));
604 p += width;
605 }
606 else {
607 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
608 }
609
610 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
611
612 /* Write stencil values */
613 if (zoom) {
614 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
615 destx, dy, stencil);
616 }
617 else {
618 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
619 }
620 }
621
622 if (overlapping)
623 _mesa_free(tmpImage);
624 }
625
626
627 /**
628 * This isn't terribly efficient. If a driver really has combined
629 * depth/stencil buffers the driver should implement an optimized
630 * CopyPixels function.
631 */
632 static void
633 copy_depth_stencil_pixels(GLcontext *ctx,
634 const GLint srcX, const GLint srcY,
635 const GLint width, const GLint height,
636 const GLint destX, const GLint destY)
637 {
638 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
639 GLint sy, dy, stepy;
640 GLint j;
641 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
642 GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
643 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
644 const GLuint stencilMask = ctx->Stencil.WriteMask[0];
645 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
646 const GLboolean scaleOrBias
647 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
648 GLint overlapping;
649
650 depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
651 depthReadRb = ctx->ReadBuffer->_DepthBuffer;
652 stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
653
654 ASSERT(depthDrawRb);
655 ASSERT(depthReadRb);
656 ASSERT(stencilReadRb);
657
658 if (ctx->DrawBuffer == ctx->ReadBuffer) {
659 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
660 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
661 }
662 else {
663 overlapping = GL_FALSE;
664 }
665
666 /* Determine if copy should be bottom-to-top or top-to-bottom */
667 if (!overlapping && srcY < destY) {
668 /* top-down max-to-min */
669 sy = srcY + height - 1;
670 dy = destY + height - 1;
671 stepy = -1;
672 }
673 else {
674 /* bottom-up min-to-max */
675 sy = srcY;
676 dy = destY;
677 stepy = 1;
678 }
679
680 if (overlapping) {
681 GLint ssy = sy;
682
683 if (stencilMask != 0x0) {
684 tempStencilImage
685 = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
686 if (!tempStencilImage) {
687 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
688 return;
689 }
690
691 /* get copy of stencil pixels */
692 stencilPtr = tempStencilImage;
693 for (j = 0; j < height; j++, ssy += stepy) {
694 _swrast_read_stencil_span(ctx, stencilReadRb,
695 width, srcX, ssy, stencilPtr);
696 stencilPtr += width;
697 }
698 stencilPtr = tempStencilImage;
699 }
700
701 if (ctx->Depth.Mask) {
702 tempDepthImage
703 = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
704 if (!tempDepthImage) {
705 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
706 _mesa_free(tempStencilImage);
707 return;
708 }
709
710 /* get copy of depth pixels */
711 depthPtr = tempDepthImage;
712 for (j = 0; j < height; j++, ssy += stepy) {
713 _swrast_read_depth_span_float(ctx, depthReadRb,
714 width, srcX, ssy, depthPtr);
715 depthPtr += width;
716 }
717 depthPtr = tempDepthImage;
718 }
719 }
720
721 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
722 if (stencilMask != 0x0) {
723 GLstencil stencil[MAX_WIDTH];
724
725 /* Get stencil values */
726 if (overlapping) {
727 _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
728 stencilPtr += width;
729 }
730 else {
731 _swrast_read_stencil_span(ctx, stencilReadRb,
732 width, srcX, sy, stencil);
733 }
734
735 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
736
737 /* Write values */
738 if (zoom) {
739 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
740 destX, dy, stencil);
741 }
742 else {
743 _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
744 }
745 }
746
747 if (ctx->Depth.Mask) {
748 GLfloat depth[MAX_WIDTH];
749 GLuint zVals32[MAX_WIDTH];
750 GLushort zVals16[MAX_WIDTH];
751 GLvoid *zVals;
752 GLuint zBytes;
753
754 /* get depth values */
755 if (overlapping) {
756 _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat));
757 depthPtr += width;
758 }
759 else {
760 _swrast_read_depth_span_float(ctx, depthReadRb,
761 width, srcX, sy, depth);
762 }
763
764 /* scale & bias */
765 if (scaleOrBias) {
766 _mesa_scale_and_bias_depth(ctx, width, depth);
767 }
768 /* convert to integer Z values */
769 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
770 GLint k;
771 for (k = 0; k < width; k++)
772 zVals16[k] = (GLushort) (depth[k] * depthScale);
773 zVals = zVals16;
774 zBytes = 2;
775 }
776 else {
777 GLint k;
778 for (k = 0; k < width; k++)
779 zVals32[k] = (GLuint) (depth[k] * depthScale);
780 zVals = zVals32;
781 zBytes = 4;
782 }
783
784 /* Write values */
785 if (zoom) {
786 _swrast_write_zoomed_z_span(ctx, destX, destY, width,
787 destX, dy, zVals);
788 }
789 else {
790 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
791 }
792 }
793 }
794
795 if (tempStencilImage)
796 _mesa_free(tempStencilImage);
797
798 if (tempDepthImage)
799 _mesa_free(tempDepthImage);
800 }
801
802
803
804 /**
805 * Try to do a fast copy pixels.
806 */
807 static GLboolean
808 fast_copy_pixels(GLcontext *ctx,
809 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
810 GLint dstX, GLint dstY, GLenum type)
811 {
812 struct gl_framebuffer *srcFb = ctx->ReadBuffer;
813 struct gl_framebuffer *dstFb = ctx->DrawBuffer;
814 struct gl_renderbuffer *srcRb, *dstRb;
815 GLint row, yStep;
816
817 if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
818 ctx->Pixel.ZoomX != 1.0F ||
819 ctx->Pixel.ZoomY != 1.0F ||
820 ctx->_ImageTransferState) {
821 /* can't handle these */
822 return GL_FALSE;
823 }
824
825 if (type == GL_COLOR) {
826 if (dstFb->_NumColorDrawBuffers[0] != 1)
827 return GL_FALSE;
828 srcRb = srcFb->_ColorReadBuffer;
829 dstRb = dstFb->_ColorDrawBuffers[0][0];
830 }
831 else if (type == GL_STENCIL) {
832 srcRb = srcFb->_StencilBuffer;
833 dstRb = dstFb->_StencilBuffer;
834 }
835 else if (type == GL_DEPTH) {
836 srcRb = srcFb->_DepthBuffer;
837 dstRb = dstFb->_DepthBuffer;
838 }
839 else {
840 ASSERT(type == GL_DEPTH_STENCIL_EXT);
841 /* XXX correct? */
842 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
843 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
844 }
845
846 /* src and dst renderbuffers must be same format and type */
847 if (!srcRb || !dstRb ||
848 srcRb->DataType != dstRb->DataType ||
849 srcRb->_BaseFormat != dstRb->_BaseFormat) {
850 return GL_FALSE;
851 }
852
853 /* clipping not supported */
854 if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
855 srcY < 0 || srcY + height > (GLint) srcFb->Height ||
856 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
857 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
858 return GL_FALSE;
859 }
860
861 /* overlapping src/dst doesn't matter, just determine Y direction */
862 if (srcY < dstY) {
863 /* top-down max-to-min */
864 srcY = srcY + height - 1;
865 dstY = dstY + height - 1;
866 yStep = -1;
867 }
868 else {
869 /* bottom-up min-to-max */
870 yStep = 1;
871 }
872
873 for (row = 0; row < height; row++) {
874 GLuint temp[MAX_WIDTH][4];
875 srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
876 dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
877 srcY += yStep;
878 dstY += yStep;
879 }
880
881 return GL_TRUE;
882 }
883
884
885 /**
886 * Do software-based glCopyPixels.
887 * By time we get here, all parameters will have been error-checked.
888 */
889 void
890 _swrast_CopyPixels( GLcontext *ctx,
891 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
892 GLint destx, GLint desty, GLenum type )
893 {
894 SWcontext *swrast = SWRAST_CONTEXT(ctx);
895 RENDER_START(swrast,ctx);
896
897 if (swrast->NewState)
898 _swrast_validate_derived( ctx );
899
900 if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
901 switch (type) {
902 case GL_COLOR:
903 if (ctx->Visual.rgbMode) {
904 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
905 }
906 else {
907 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
908 }
909 break;
910 case GL_DEPTH:
911 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
912 break;
913 case GL_STENCIL:
914 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
915 break;
916 case GL_DEPTH_STENCIL_EXT:
917 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
918 break;
919 default:
920 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
921 }
922 }
923
924 RENDER_FINISH(swrast,ctx);
925 }