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