a9b4cb808182f70e96316cb7d5c61e3aa8237f90
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
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 "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/condrender.h"
30 #include "main/convolve.h"
31 #include "main/image.h"
32 #include "main/macros.h"
33 #include "main/imports.h"
34
35 #include "s_context.h"
36 #include "s_depth.h"
37 #include "s_span.h"
38 #include "s_stencil.h"
39 #include "s_zoom.h"
40
41
42
43 /**
44 * Determine if there's overlap in an image copy.
45 * This test also compensates for the fact that copies are done from
46 * bottom to top and overlaps can sometimes be handled correctly
47 * without making a temporary image copy.
48 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
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 + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
74 /* src is completely right of dest */
75 return GL_FALSE;
76 }
77 else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
78 /* src is completely left of dest */
79 return GL_FALSE;
80 }
81 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
82 /* src is completely below dest */
83 return GL_FALSE;
84 }
85 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
86 /* src is completely above dest */
87 return GL_FALSE;
88 }
89 else {
90 return GL_TRUE;
91 }
92 }
93 }
94
95
96 /**
97 * RGBA copypixels with convolution.
98 */
99 static void
100 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
101 GLint width, GLint height, GLint destx, GLint desty)
102 {
103 GLint row;
104 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
105 const GLbitfield transferOps = ctx->_ImageTransferState;
106 GLfloat *dest, *tmpImage, *convImage;
107 SWspan span;
108
109 INIT_SPAN(span, GL_BITMAP);
110 _swrast_span_default_attribs(ctx, &span);
111 span.arrayMask = SPAN_RGBA;
112 span.arrayAttribs = FRAG_BIT_COL0;
113
114 /* allocate space for GLfloat image */
115 tmpImage = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
116 if (!tmpImage) {
117 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
118 return;
119 }
120 convImage = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
121 if (!convImage) {
122 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 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 /* write the new image */
162 for (row = 0; row < height; row++) {
163 const GLfloat *src = convImage + row * width * 4;
164 GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
165
166 /* copy convolved colors into span array */
167 memcpy(rgba, src, width * 4 * sizeof(GLfloat));
168
169 /* write span */
170 span.x = destx;
171 span.y = desty + row;
172 span.end = width;
173 span.array->ChanType = GL_FLOAT;
174 if (zoom) {
175 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
176 }
177 else {
178 _swrast_write_rgba_span(ctx, &span);
179 }
180 }
181 /* restore this */
182 span.array->ChanType = CHAN_TYPE;
183
184 free(convImage);
185 }
186
187
188 /**
189 * RGBA copypixels
190 */
191 static void
192 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
193 GLint width, GLint height, GLint destx, GLint desty)
194 {
195 GLfloat *tmpImage, *p;
196 GLint sy, dy, stepy, row;
197 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
198 GLint overlapping;
199 GLuint transferOps = ctx->_ImageTransferState;
200 SWspan span;
201
202 if (!ctx->ReadBuffer->_ColorReadBuffer) {
203 /* no readbuffer - OK */
204 return;
205 }
206
207 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
208 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
209 return;
210 }
211 else if (ctx->Pixel.Convolution1DEnabled) {
212 /* make sure we don't apply 1D convolution */
213 transferOps &= ~(IMAGE_CONVOLUTION_BIT |
214 IMAGE_POST_CONVOLUTION_SCALE_BIAS);
215 }
216
217 if (ctx->DrawBuffer == ctx->ReadBuffer) {
218 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
219 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
220 }
221 else {
222 overlapping = GL_FALSE;
223 }
224
225 /* Determine if copy should be done bottom-to-top or top-to-bottom */
226 if (!overlapping && srcy < desty) {
227 /* top-down max-to-min */
228 sy = srcy + height - 1;
229 dy = desty + height - 1;
230 stepy = -1;
231 }
232 else {
233 /* bottom-up min-to-max */
234 sy = srcy;
235 dy = desty;
236 stepy = 1;
237 }
238
239 INIT_SPAN(span, GL_BITMAP);
240 _swrast_span_default_attribs(ctx, &span);
241 span.arrayMask = SPAN_RGBA;
242 span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */
243
244 if (overlapping) {
245 tmpImage = (GLfloat *) malloc(width * height * sizeof(GLfloat) * 4);
246 if (!tmpImage) {
247 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
248 return;
249 }
250 /* read the source image as RGBA/float */
251 p = tmpImage;
252 for (row = 0; row < height; row++) {
253 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
254 width, srcx, sy + row, GL_FLOAT, p );
255 p += width * 4;
256 }
257 p = tmpImage;
258 }
259 else {
260 tmpImage = NULL; /* silence compiler warnings */
261 p = NULL;
262 }
263
264 ASSERT(width < MAX_WIDTH);
265
266 for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
267 GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];
268
269 /* Get row/span of source pixels */
270 if (overlapping) {
271 /* get from buffered image */
272 memcpy(rgba, p, width * sizeof(GLfloat) * 4);
273 p += width * 4;
274 }
275 else {
276 /* get from framebuffer */
277 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
278 width, srcx, sy, GL_FLOAT, rgba );
279 }
280
281 if (transferOps) {
282 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
283 (GLfloat (*)[4]) rgba);
284 }
285
286 /* Write color span */
287 span.x = destx;
288 span.y = dy;
289 span.end = width;
290 span.array->ChanType = GL_FLOAT;
291 if (zoom) {
292 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
293 }
294 else {
295 _swrast_write_rgba_span(ctx, &span);
296 }
297 }
298
299 span.array->ChanType = CHAN_TYPE; /* restore */
300
301 if (overlapping)
302 free(tmpImage);
303 }
304
305
306 /**
307 * Convert floating point Z values to integer Z values with pixel transfer's
308 * Z scale and bias.
309 */
310 static void
311 scale_and_bias_z(GLcontext *ctx, GLuint width,
312 const GLfloat depth[], GLuint z[])
313 {
314 const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
315 GLuint i;
316
317 if (depthMax <= 0xffffff &&
318 ctx->Pixel.DepthScale == 1.0 &&
319 ctx->Pixel.DepthBias == 0.0) {
320 /* no scale or bias and no clamping and no worry of overflow */
321 const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
322 for (i = 0; i < width; i++) {
323 z[i] = (GLuint) (depth[i] * depthMaxF);
324 }
325 }
326 else {
327 /* need to be careful with overflow */
328 const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
329 for (i = 0; i < width; i++) {
330 GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
331 d = CLAMP(d, 0.0, 1.0) * depthMaxF;
332 if (d >= depthMaxF)
333 z[i] = depthMax;
334 else
335 z[i] = (GLuint) d;
336 }
337 }
338 }
339
340
341
342 /*
343 * TODO: Optimize!!!!
344 */
345 static void
346 copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
347 GLint width, GLint height,
348 GLint destx, GLint desty )
349 {
350 struct gl_framebuffer *fb = ctx->ReadBuffer;
351 struct gl_renderbuffer *readRb = fb->_DepthBuffer;
352 GLfloat *p, *tmpImage;
353 GLint sy, dy, stepy;
354 GLint j;
355 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
356 GLint overlapping;
357 SWspan span;
358
359 if (!readRb) {
360 /* no readbuffer - OK */
361 return;
362 }
363
364 INIT_SPAN(span, GL_BITMAP);
365 _swrast_span_default_attribs(ctx, &span);
366 span.arrayMask = SPAN_Z;
367
368 if (ctx->DrawBuffer == ctx->ReadBuffer) {
369 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
370 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
371 }
372 else {
373 overlapping = GL_FALSE;
374 }
375
376 /* Determine if copy should be bottom-to-top or top-to-bottom */
377 if (!overlapping && srcy < desty) {
378 /* top-down max-to-min */
379 sy = srcy + height - 1;
380 dy = desty + height - 1;
381 stepy = -1;
382 }
383 else {
384 /* bottom-up min-to-max */
385 sy = srcy;
386 dy = desty;
387 stepy = 1;
388 }
389
390 if (overlapping) {
391 GLint ssy = sy;
392 tmpImage = (GLfloat *) malloc(width * height * sizeof(GLfloat));
393 if (!tmpImage) {
394 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
395 return;
396 }
397 p = tmpImage;
398 for (j = 0; j < height; j++, ssy += stepy) {
399 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
400 p += width;
401 }
402 p = tmpImage;
403 }
404 else {
405 tmpImage = NULL; /* silence compiler warning */
406 p = NULL;
407 }
408
409 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
410 GLfloat depth[MAX_WIDTH];
411 /* get depth values */
412 if (overlapping) {
413 memcpy(depth, p, width * sizeof(GLfloat));
414 p += width;
415 }
416 else {
417 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
418 }
419
420 /* apply scale and bias */
421 scale_and_bias_z(ctx, width, depth, span.array->z);
422
423 /* write depth values */
424 span.x = destx;
425 span.y = dy;
426 span.end = width;
427 if (zoom)
428 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
429 else
430 _swrast_write_rgba_span(ctx, &span);
431 }
432
433 if (overlapping)
434 free(tmpImage);
435 }
436
437
438
439 static void
440 copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
441 GLint width, GLint height,
442 GLint destx, GLint desty )
443 {
444 struct gl_framebuffer *fb = ctx->ReadBuffer;
445 struct gl_renderbuffer *rb = fb->_StencilBuffer;
446 GLint sy, dy, stepy;
447 GLint j;
448 GLstencil *p, *tmpImage;
449 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
450 GLint overlapping;
451
452 if (!rb) {
453 /* no readbuffer - OK */
454 return;
455 }
456
457 if (ctx->DrawBuffer == ctx->ReadBuffer) {
458 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
459 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
460 }
461 else {
462 overlapping = GL_FALSE;
463 }
464
465 /* Determine if copy should be bottom-to-top or top-to-bottom */
466 if (!overlapping && srcy < desty) {
467 /* top-down max-to-min */
468 sy = srcy + height - 1;
469 dy = desty + height - 1;
470 stepy = -1;
471 }
472 else {
473 /* bottom-up min-to-max */
474 sy = srcy;
475 dy = desty;
476 stepy = 1;
477 }
478
479 if (overlapping) {
480 GLint ssy = sy;
481 tmpImage = (GLstencil *) malloc(width * height * sizeof(GLstencil));
482 if (!tmpImage) {
483 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
484 return;
485 }
486 p = tmpImage;
487 for (j = 0; j < height; j++, ssy += stepy) {
488 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
489 p += width;
490 }
491 p = tmpImage;
492 }
493 else {
494 tmpImage = NULL; /* silence compiler warning */
495 p = NULL;
496 }
497
498 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
499 GLstencil stencil[MAX_WIDTH];
500
501 /* Get stencil values */
502 if (overlapping) {
503 memcpy(stencil, p, width * sizeof(GLstencil));
504 p += width;
505 }
506 else {
507 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
508 }
509
510 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
511
512 /* Write stencil values */
513 if (zoom) {
514 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
515 destx, dy, stencil);
516 }
517 else {
518 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
519 }
520 }
521
522 if (overlapping)
523 free(tmpImage);
524 }
525
526
527 /**
528 * This isn't terribly efficient. If a driver really has combined
529 * depth/stencil buffers the driver should implement an optimized
530 * CopyPixels function.
531 */
532 static void
533 copy_depth_stencil_pixels(GLcontext *ctx,
534 const GLint srcX, const GLint srcY,
535 const GLint width, const GLint height,
536 const GLint destX, const GLint destY)
537 {
538 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
539 GLint sy, dy, stepy;
540 GLint j;
541 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
542 GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
543 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
544 const GLuint stencilMask = ctx->Stencil.WriteMask[0];
545 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
546 const GLboolean scaleOrBias
547 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
548 GLint overlapping;
549
550 depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
551 depthReadRb = ctx->ReadBuffer->_DepthBuffer;
552 stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
553
554 ASSERT(depthDrawRb);
555 ASSERT(depthReadRb);
556 ASSERT(stencilReadRb);
557
558 if (ctx->DrawBuffer == ctx->ReadBuffer) {
559 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
560 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
561 }
562 else {
563 overlapping = GL_FALSE;
564 }
565
566 /* Determine if copy should be bottom-to-top or top-to-bottom */
567 if (!overlapping && srcY < destY) {
568 /* top-down max-to-min */
569 sy = srcY + height - 1;
570 dy = destY + height - 1;
571 stepy = -1;
572 }
573 else {
574 /* bottom-up min-to-max */
575 sy = srcY;
576 dy = destY;
577 stepy = 1;
578 }
579
580 if (overlapping) {
581 GLint ssy = sy;
582
583 if (stencilMask != 0x0) {
584 tempStencilImage
585 = (GLstencil *) malloc(width * height * sizeof(GLstencil));
586 if (!tempStencilImage) {
587 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
588 return;
589 }
590
591 /* get copy of stencil pixels */
592 stencilPtr = tempStencilImage;
593 for (j = 0; j < height; j++, ssy += stepy) {
594 _swrast_read_stencil_span(ctx, stencilReadRb,
595 width, srcX, ssy, stencilPtr);
596 stencilPtr += width;
597 }
598 stencilPtr = tempStencilImage;
599 }
600
601 if (ctx->Depth.Mask) {
602 tempDepthImage
603 = (GLfloat *) malloc(width * height * sizeof(GLfloat));
604 if (!tempDepthImage) {
605 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
606 free(tempStencilImage);
607 return;
608 }
609
610 /* get copy of depth pixels */
611 depthPtr = tempDepthImage;
612 for (j = 0; j < height; j++, ssy += stepy) {
613 _swrast_read_depth_span_float(ctx, depthReadRb,
614 width, srcX, ssy, depthPtr);
615 depthPtr += width;
616 }
617 depthPtr = tempDepthImage;
618 }
619 }
620
621 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
622 if (stencilMask != 0x0) {
623 GLstencil stencil[MAX_WIDTH];
624
625 /* Get stencil values */
626 if (overlapping) {
627 memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
628 stencilPtr += width;
629 }
630 else {
631 _swrast_read_stencil_span(ctx, stencilReadRb,
632 width, srcX, sy, stencil);
633 }
634
635 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
636
637 /* Write values */
638 if (zoom) {
639 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
640 destX, dy, stencil);
641 }
642 else {
643 _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
644 }
645 }
646
647 if (ctx->Depth.Mask) {
648 GLfloat depth[MAX_WIDTH];
649 GLuint zVals32[MAX_WIDTH];
650 GLushort zVals16[MAX_WIDTH];
651 GLvoid *zVals;
652 GLuint zBytes;
653
654 /* get depth values */
655 if (overlapping) {
656 memcpy(depth, depthPtr, width * sizeof(GLfloat));
657 depthPtr += width;
658 }
659 else {
660 _swrast_read_depth_span_float(ctx, depthReadRb,
661 width, srcX, sy, depth);
662 }
663
664 /* scale & bias */
665 if (scaleOrBias) {
666 _mesa_scale_and_bias_depth(ctx, width, depth);
667 }
668 /* convert to integer Z values */
669 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
670 GLint k;
671 for (k = 0; k < width; k++)
672 zVals16[k] = (GLushort) (depth[k] * depthScale);
673 zVals = zVals16;
674 zBytes = 2;
675 }
676 else {
677 GLint k;
678 for (k = 0; k < width; k++)
679 zVals32[k] = (GLuint) (depth[k] * depthScale);
680 zVals = zVals32;
681 zBytes = 4;
682 }
683
684 /* Write values */
685 if (zoom) {
686 _swrast_write_zoomed_z_span(ctx, destX, destY, width,
687 destX, dy, zVals);
688 }
689 else {
690 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
691 }
692 }
693 }
694
695 if (tempStencilImage)
696 free(tempStencilImage);
697
698 if (tempDepthImage)
699 free(tempDepthImage);
700 }
701
702
703
704 /**
705 * Try to do a fast copy pixels.
706 */
707 static GLboolean
708 fast_copy_pixels(GLcontext *ctx,
709 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
710 GLint dstX, GLint dstY, GLenum type)
711 {
712 struct gl_framebuffer *srcFb = ctx->ReadBuffer;
713 struct gl_framebuffer *dstFb = ctx->DrawBuffer;
714 struct gl_renderbuffer *srcRb, *dstRb;
715 GLint row, yStep;
716
717 if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
718 ctx->Pixel.ZoomX != 1.0F ||
719 ctx->Pixel.ZoomY != 1.0F ||
720 ctx->_ImageTransferState) {
721 /* can't handle these */
722 return GL_FALSE;
723 }
724
725 if (type == GL_COLOR) {
726 if (dstFb->_NumColorDrawBuffers != 1)
727 return GL_FALSE;
728 srcRb = srcFb->_ColorReadBuffer;
729 dstRb = dstFb->_ColorDrawBuffers[0];
730 }
731 else if (type == GL_STENCIL) {
732 srcRb = srcFb->_StencilBuffer;
733 dstRb = dstFb->_StencilBuffer;
734 }
735 else if (type == GL_DEPTH) {
736 srcRb = srcFb->_DepthBuffer;
737 dstRb = dstFb->_DepthBuffer;
738 }
739 else {
740 ASSERT(type == GL_DEPTH_STENCIL_EXT);
741 /* XXX correct? */
742 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
743 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
744 }
745
746 /* src and dst renderbuffers must be same format and type */
747 if (!srcRb || !dstRb ||
748 srcRb->DataType != dstRb->DataType ||
749 srcRb->_BaseFormat != dstRb->_BaseFormat) {
750 return GL_FALSE;
751 }
752
753 /* clipping not supported */
754 if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
755 srcY < 0 || srcY + height > (GLint) srcFb->Height ||
756 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
757 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
758 return GL_FALSE;
759 }
760
761 /* overlapping src/dst doesn't matter, just determine Y direction */
762 if (srcY < dstY) {
763 /* top-down max-to-min */
764 srcY = srcY + height - 1;
765 dstY = dstY + height - 1;
766 yStep = -1;
767 }
768 else {
769 /* bottom-up min-to-max */
770 yStep = 1;
771 }
772
773 for (row = 0; row < height; row++) {
774 GLuint temp[MAX_WIDTH][4];
775 srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
776 dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
777 srcY += yStep;
778 dstY += yStep;
779 }
780
781 return GL_TRUE;
782 }
783
784
785 /**
786 * Do software-based glCopyPixels.
787 * By time we get here, all parameters will have been error-checked.
788 */
789 void
790 _swrast_CopyPixels( GLcontext *ctx,
791 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
792 GLint destx, GLint desty, GLenum type )
793 {
794 SWcontext *swrast = SWRAST_CONTEXT(ctx);
795 swrast_render_start(ctx);
796
797 if (!_mesa_check_conditional_render(ctx))
798 return; /* don't copy */
799
800 if (swrast->NewState)
801 _swrast_validate_derived( ctx );
802
803 if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
804 switch (type) {
805 case GL_COLOR:
806 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
807 break;
808 case GL_DEPTH:
809 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
810 break;
811 case GL_STENCIL:
812 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
813 break;
814 case GL_DEPTH_STENCIL_EXT:
815 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
816 break;
817 default:
818 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
819 }
820 }
821
822 swrast_render_finish(ctx);
823 }