2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/convolve.h"
30 #include "main/histogram.h"
31 #include "main/image.h"
32 #include "main/macros.h"
33 #include "main/imports.h"
34 #include "main/pixel.h"
36 #include "s_context.h"
39 #include "s_stencil.h"
47 * Determine if there's overlap in an image copy.
48 * This test also compensates for the fact that copies are done from
49 * bottom to top and overlaps can sometimes be handled correctly
50 * without making a temporary image copy.
51 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
54 regions_overlap(GLint srcx, GLint srcy,
55 GLint dstx, GLint dsty,
56 GLint width, GLint height,
57 GLfloat zoomX, GLfloat zoomY)
59 if (zoomX == 1.0 && zoomY == 1.0) {
61 if (srcx >= dstx + width || (srcx + width <= dstx)) {
64 else if (srcy < dsty) { /* this is OK */
67 else if (srcy > dsty + height) {
75 /* add one pixel of slop when zooming, just to be safe */
76 if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
77 /* src is completely right of dest */
80 else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
81 /* src is completely left of dest */
84 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
85 /* src is completely below dest */
88 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
89 /* src is completely above dest */
100 * RGBA copypixels with convolution.
103 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
104 GLint width, GLint height, GLint destx, GLint desty)
107 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
108 const GLbitfield transferOps = ctx->_ImageTransferState;
109 const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
110 || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
111 GLfloat *dest, *tmpImage, *convImage;
114 INIT_SPAN(span, GL_BITMAP);
115 _swrast_span_default_attribs(ctx, &span);
116 span.arrayMask = SPAN_RGBA;
117 span.arrayAttribs = FRAG_BIT_COL0;
119 /* allocate space for GLfloat image */
120 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
122 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
125 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
127 _mesa_free(tmpImage);
128 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
132 /* read source image as float/RGBA */
134 for (row = 0; row < height; row++) {
135 _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
136 width, srcx, srcy + row, GL_FLOAT, dest);
140 /* do the image transfer ops which preceed convolution */
141 for (row = 0; row < height; row++) {
142 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
143 _mesa_apply_rgba_transfer_ops(ctx,
144 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
149 if (ctx->Pixel.Convolution2DEnabled) {
150 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
153 ASSERT(ctx->Pixel.Separable2DEnabled);
154 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
156 _mesa_free(tmpImage);
158 /* do remaining post-convolution image transfer ops */
159 for (row = 0; row < height; row++) {
160 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
161 _mesa_apply_rgba_transfer_ops(ctx,
162 transferOps & IMAGE_POST_CONVOLUTION_BITS,
167 /* write the new image */
168 for (row = 0; row < height; row++) {
169 const GLfloat *src = convImage + row * width * 4;
170 GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
172 /* copy convolved colors into span array */
173 _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat));
177 span.y = desty + row;
179 span.array->ChanType = GL_FLOAT;
181 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
184 _swrast_write_rgba_span(ctx, &span);
188 span.array->ChanType = CHAN_TYPE;
191 _mesa_free(convImage);
199 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
200 GLint width, GLint height, GLint destx, GLint desty)
202 GLfloat *tmpImage, *p;
203 GLint sy, dy, stepy, row;
204 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
206 GLuint transferOps = ctx->_ImageTransferState;
209 if (!ctx->ReadBuffer->_ColorReadBuffer) {
210 /* no readbuffer - OK */
214 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
215 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
218 else if (ctx->Pixel.Convolution1DEnabled) {
219 /* make sure we don't apply 1D convolution */
220 transferOps &= ~(IMAGE_CONVOLUTION_BIT |
221 IMAGE_POST_CONVOLUTION_SCALE_BIAS);
224 if (ctx->DrawBuffer == ctx->ReadBuffer) {
225 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
226 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
229 overlapping = GL_FALSE;
232 /* Determine if copy should be done bottom-to-top or top-to-bottom */
233 if (!overlapping && srcy < desty) {
234 /* top-down max-to-min */
235 sy = srcy + height - 1;
236 dy = desty + height - 1;
240 /* bottom-up min-to-max */
246 INIT_SPAN(span, GL_BITMAP);
247 _swrast_span_default_attribs(ctx, &span);
248 span.arrayMask = SPAN_RGBA;
249 span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */
252 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4);
254 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
257 /* read the source image as RGBA/float */
259 for (row = 0; row < height; row++) {
260 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
261 width, srcx, sy + row, GL_FLOAT, p );
267 tmpImage = NULL; /* silence compiler warnings */
271 ASSERT(width < MAX_WIDTH);
273 for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
274 GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];
276 /* Get row/span of source pixels */
278 /* get from buffered image */
279 _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4);
283 /* get from framebuffer */
284 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
285 width, srcx, sy, GL_FLOAT, rgba );
289 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
290 (GLfloat (*)[4]) rgba);
293 /* Write color span */
297 span.array->ChanType = GL_FLOAT;
299 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
302 _swrast_write_rgba_span(ctx, &span);
306 span.array->ChanType = CHAN_TYPE; /* restore */
309 _mesa_free(tmpImage);
314 copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
315 GLint width, GLint height,
316 GLint destx, GLint desty )
321 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
325 if (!ctx->ReadBuffer->_ColorReadBuffer) {
326 /* no readbuffer - OK */
330 INIT_SPAN(span, GL_BITMAP);
331 _swrast_span_default_attribs(ctx, &span);
332 span.arrayMask = SPAN_INDEX;
334 if (ctx->DrawBuffer == ctx->ReadBuffer) {
335 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
336 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
339 overlapping = GL_FALSE;
342 /* Determine if copy should be bottom-to-top or top-to-bottom */
343 if (!overlapping && srcy < desty) {
344 /* top-down max-to-min */
345 sy = srcy + height - 1;
346 dy = desty + height - 1;
350 /* bottom-up min-to-max */
358 tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
360 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
365 for (j = 0; j < height; j++, ssy += stepy) {
366 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
367 width, srcx, ssy, p );
373 tmpImage = NULL; /* silence compiler warning */
377 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
378 /* Get color indexes */
380 _mesa_memcpy(span.array->index, p, width * sizeof(GLuint));
384 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
385 width, srcx, sy, span.array->index );
388 if (ctx->_ImageTransferState)
389 _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState,
390 width, span.array->index);
392 /* write color indexes */
397 _swrast_write_zoomed_index_span(ctx, destx, desty, &span);
399 _swrast_write_index_span(ctx, &span);
403 _mesa_free(tmpImage);
408 * Convert floating point Z values to integer Z values with pixel transfer's
412 scale_and_bias_z(GLcontext *ctx, GLuint width,
413 const GLfloat depth[], GLuint z[])
415 const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
418 if (depthMax <= 0xffffff &&
419 ctx->Pixel.DepthScale == 1.0 &&
420 ctx->Pixel.DepthBias == 0.0) {
421 /* no scale or bias and no clamping and no worry of overflow */
422 const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
423 for (i = 0; i < width; i++) {
424 z[i] = (GLuint) (depth[i] * depthMaxF);
428 /* need to be careful with overflow */
429 const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
430 for (i = 0; i < width; i++) {
431 GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
432 d = CLAMP(d, 0.0, 1.0) * depthMaxF;
447 copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
448 GLint width, GLint height,
449 GLint destx, GLint desty )
451 struct gl_framebuffer *fb = ctx->ReadBuffer;
452 struct gl_renderbuffer *readRb = fb->_DepthBuffer;
453 GLfloat *p, *tmpImage;
456 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
461 /* no readbuffer - OK */
465 INIT_SPAN(span, GL_BITMAP);
466 _swrast_span_default_attribs(ctx, &span);
467 span.arrayMask = SPAN_Z;
469 if (ctx->DrawBuffer == ctx->ReadBuffer) {
470 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
471 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
474 overlapping = GL_FALSE;
477 /* Determine if copy should be bottom-to-top or top-to-bottom */
478 if (!overlapping && srcy < desty) {
479 /* top-down max-to-min */
480 sy = srcy + height - 1;
481 dy = desty + height - 1;
485 /* bottom-up min-to-max */
493 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
495 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
499 for (j = 0; j < height; j++, ssy += stepy) {
500 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
506 tmpImage = NULL; /* silence compiler warning */
510 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
511 GLfloat depth[MAX_WIDTH];
512 /* get depth values */
514 _mesa_memcpy(depth, p, width * sizeof(GLfloat));
518 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
521 /* apply scale and bias */
522 scale_and_bias_z(ctx, width, depth, span.array->z);
524 /* write depth values */
528 if (fb->Visual.rgbMode) {
530 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
532 _swrast_write_rgba_span(ctx, &span);
536 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
538 _swrast_write_index_span(ctx, &span);
543 _mesa_free(tmpImage);
549 copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
550 GLint width, GLint height,
551 GLint destx, GLint desty )
553 struct gl_framebuffer *fb = ctx->ReadBuffer;
554 struct gl_renderbuffer *rb = fb->_StencilBuffer;
557 GLstencil *p, *tmpImage;
558 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
562 /* no readbuffer - OK */
566 if (ctx->DrawBuffer == ctx->ReadBuffer) {
567 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
568 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
571 overlapping = GL_FALSE;
574 /* Determine if copy should be bottom-to-top or top-to-bottom */
575 if (!overlapping && srcy < desty) {
576 /* top-down max-to-min */
577 sy = srcy + height - 1;
578 dy = desty + height - 1;
582 /* bottom-up min-to-max */
590 tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
592 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
596 for (j = 0; j < height; j++, ssy += stepy) {
597 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
603 tmpImage = NULL; /* silence compiler warning */
607 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
608 GLstencil stencil[MAX_WIDTH];
610 /* Get stencil values */
612 _mesa_memcpy(stencil, p, width * sizeof(GLstencil));
616 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
619 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
621 /* Write stencil values */
623 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
627 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
632 _mesa_free(tmpImage);
637 * This isn't terribly efficient. If a driver really has combined
638 * depth/stencil buffers the driver should implement an optimized
639 * CopyPixels function.
642 copy_depth_stencil_pixels(GLcontext *ctx,
643 const GLint srcX, const GLint srcY,
644 const GLint width, const GLint height,
645 const GLint destX, const GLint destY)
647 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
650 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
651 GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
652 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
653 const GLuint stencilMask = ctx->Stencil.WriteMask[0];
654 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
655 const GLboolean scaleOrBias
656 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
659 depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
660 depthReadRb = ctx->ReadBuffer->_DepthBuffer;
661 stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
665 ASSERT(stencilReadRb);
667 if (ctx->DrawBuffer == ctx->ReadBuffer) {
668 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
669 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
672 overlapping = GL_FALSE;
675 /* Determine if copy should be bottom-to-top or top-to-bottom */
676 if (!overlapping && srcY < destY) {
677 /* top-down max-to-min */
678 sy = srcY + height - 1;
679 dy = destY + height - 1;
683 /* bottom-up min-to-max */
692 if (stencilMask != 0x0) {
694 = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
695 if (!tempStencilImage) {
696 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
700 /* get copy of stencil pixels */
701 stencilPtr = tempStencilImage;
702 for (j = 0; j < height; j++, ssy += stepy) {
703 _swrast_read_stencil_span(ctx, stencilReadRb,
704 width, srcX, ssy, stencilPtr);
707 stencilPtr = tempStencilImage;
710 if (ctx->Depth.Mask) {
712 = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
713 if (!tempDepthImage) {
714 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
715 _mesa_free(tempStencilImage);
719 /* get copy of depth pixels */
720 depthPtr = tempDepthImage;
721 for (j = 0; j < height; j++, ssy += stepy) {
722 _swrast_read_depth_span_float(ctx, depthReadRb,
723 width, srcX, ssy, depthPtr);
726 depthPtr = tempDepthImage;
730 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
731 if (stencilMask != 0x0) {
732 GLstencil stencil[MAX_WIDTH];
734 /* Get stencil values */
736 _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
740 _swrast_read_stencil_span(ctx, stencilReadRb,
741 width, srcX, sy, stencil);
744 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
748 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
752 _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
756 if (ctx->Depth.Mask) {
757 GLfloat depth[MAX_WIDTH];
758 GLuint zVals32[MAX_WIDTH];
759 GLushort zVals16[MAX_WIDTH];
763 /* get depth values */
765 _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat));
769 _swrast_read_depth_span_float(ctx, depthReadRb,
770 width, srcX, sy, depth);
775 _mesa_scale_and_bias_depth(ctx, width, depth);
777 /* convert to integer Z values */
778 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
780 for (k = 0; k < width; k++)
781 zVals16[k] = (GLushort) (depth[k] * depthScale);
787 for (k = 0; k < width; k++)
788 zVals32[k] = (GLuint) (depth[k] * depthScale);
795 _swrast_write_zoomed_z_span(ctx, destX, destY, width,
799 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
804 if (tempStencilImage)
805 _mesa_free(tempStencilImage);
808 _mesa_free(tempDepthImage);
814 * Try to do a fast copy pixels.
817 fast_copy_pixels(GLcontext *ctx,
818 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
819 GLint dstX, GLint dstY, GLenum type)
821 struct gl_framebuffer *srcFb = ctx->ReadBuffer;
822 struct gl_framebuffer *dstFb = ctx->DrawBuffer;
823 struct gl_renderbuffer *srcRb, *dstRb;
826 if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
827 ctx->Pixel.ZoomX != 1.0F ||
828 ctx->Pixel.ZoomY != 1.0F ||
829 ctx->_ImageTransferState) {
830 /* can't handle these */
834 if (type == GL_COLOR) {
835 if (dstFb->_NumColorDrawBuffers != 1)
837 srcRb = srcFb->_ColorReadBuffer;
838 dstRb = dstFb->_ColorDrawBuffers[0];
840 else if (type == GL_STENCIL) {
841 srcRb = srcFb->_StencilBuffer;
842 dstRb = dstFb->_StencilBuffer;
844 else if (type == GL_DEPTH) {
845 srcRb = srcFb->_DepthBuffer;
846 dstRb = dstFb->_DepthBuffer;
849 ASSERT(type == GL_DEPTH_STENCIL_EXT);
851 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
852 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
855 /* src and dst renderbuffers must be same format and type */
856 if (!srcRb || !dstRb ||
857 srcRb->DataType != dstRb->DataType ||
858 srcRb->_BaseFormat != dstRb->_BaseFormat) {
862 /* clipping not supported */
863 if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
864 srcY < 0 || srcY + height > (GLint) srcFb->Height ||
865 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
866 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
870 /* overlapping src/dst doesn't matter, just determine Y direction */
872 /* top-down max-to-min */
873 srcY = srcY + height - 1;
874 dstY = dstY + height - 1;
878 /* bottom-up min-to-max */
882 for (row = 0; row < height; row++) {
883 GLuint temp[MAX_WIDTH][4];
884 srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
885 dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
895 * Do software-based glCopyPixels.
896 * By time we get here, all parameters will have been error-checked.
899 _swrast_CopyPixels( GLcontext *ctx,
900 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
901 GLint destx, GLint desty, GLenum type )
903 SWcontext *swrast = SWRAST_CONTEXT(ctx);
904 swrast_render_start(ctx);
906 if (swrast->NewState)
907 _swrast_validate_derived( ctx );
909 if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
912 if (ctx->Visual.rgbMode) {
913 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
916 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
920 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
923 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
925 case GL_DEPTH_STENCIL_EXT:
926 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
929 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
933 swrast_render_finish(ctx);
937 #endif /* FEATURE_drawpix */