X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_copypix.c;h=fc5990b261c1370a43156f8360fca7446b8879f2;hb=8fb727548a652c47d8cf9593e2ae412ef2040119;hp=bfcd9cb8f7bd5cc70222a79da3d88aa09866bedf;hpb=53f82c5aadbb15585754bfacf3237093eccdb2ce;p=mesa.git diff --git a/src/mesa/swrast/s_copypix.c b/src/mesa/swrast/s_copypix.c index bfcd9cb8f7b..fc5990b261c 100644 --- a/src/mesa/swrast/s_copypix.c +++ b/src/mesa/swrast/s_copypix.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 6.1 + * Version: 7.1 * - * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,31 +23,30 @@ */ -#include "glheader.h" -#include "context.h" -#include "colormac.h" -#include "convolve.h" -#include "histogram.h" -#include "image.h" -#include "macros.h" -#include "imports.h" -#include "pixel.h" +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/convolve.h" +#include "main/histogram.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/imports.h" +#include "main/pixel.h" #include "s_context.h" #include "s_depth.h" -#include "s_pixeltex.h" #include "s_span.h" #include "s_stencil.h" -#include "s_texture.h" #include "s_zoom.h" -/* +/** * Determine if there's overlap in an image copy. * This test also compensates for the fact that copies are done from * bottom to top and overlaps can sometimes be handled correctly * without making a temporary image copy. + * \return GL_TRUE if the regions overlap, GL_FALSE otherwise. */ static GLboolean regions_overlap(GLint srcx, GLint srcy, @@ -72,13 +71,20 @@ regions_overlap(GLint srcx, GLint srcy, } else { /* add one pixel of slop when zooming, just to be safe */ - if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { + if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) { + /* src is completely right of dest */ + return GL_FALSE; + } + else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) { + /* src is completely left of dest */ return GL_FALSE; } else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { + /* src is completely below dest */ return GL_FALSE; } else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { + /* src is completely above dest */ return GL_FALSE; } else { @@ -89,113 +95,44 @@ regions_overlap(GLint srcx, GLint srcy, /** - * Convert GLfloat[n][4] colors to GLchan[n][4]. - * XXX maybe move into image.c - */ -static void -float_span_to_chan(GLuint n, CONST GLfloat in[][4], GLchan out[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - UNCLAMPED_FLOAT_TO_CHAN(out[i][RCOMP], in[i][RCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(out[i][GCOMP], in[i][GCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(out[i][BCOMP], in[i][BCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(out[i][ACOMP], in[i][ACOMP]); - } -} - - -/** - * Convert GLchan[n][4] colors to GLfloat[n][4]. - * XXX maybe move into image.c - */ -static void -chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]); - out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]); - out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]); - out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]); - } -} - - - -/* * RGBA copypixels with convolution. */ static void copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLboolean quick_draw; GLint row; - GLboolean changeBuffer; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; - const GLuint transferOps = ctx->_ImageTransferState; + const GLbitfield transferOps = ctx->_ImageTransferState; + const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) + || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink); GLfloat *dest, *tmpImage, *convImage; - struct sw_span span; - - INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); - - if (ctx->Depth.Test) - _swrast_span_default_z(ctx, &span); - if (ctx->Fog.Enabled) - _swrast_span_default_fog(ctx, &span); - - - if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 - && !zoom - && destx >= 0 - && destx + width <= (GLint) ctx->DrawBuffer->Width) { - quick_draw = GL_TRUE; - } - else { - quick_draw = GL_FALSE; - } - - /* If read and draw buffer are different we must do buffer switching */ - changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] - || ctx->DrawBuffer != ctx->ReadBuffer; + SWspan span; + INIT_SPAN(span, GL_BITMAP); + _swrast_span_default_attribs(ctx, &span); + span.arrayMask = SPAN_RGBA; + span.arrayAttribs = FRAG_BIT_COL0; /* allocate space for GLfloat image */ - tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); + tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!tmpImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } - convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); + convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!convImage) { - FREE(tmpImage); + _mesa_free(tmpImage); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } - dest = tmpImage; - - if (changeBuffer) { - /* choose the read buffer */ - _swrast_use_read_buffer(ctx); - } - - /* read source image */ + /* read source image as float/RGBA */ dest = tmpImage; for (row = 0; row < height; row++) { - GLchan rgba[MAX_WIDTH][4]; - /* Read GLchan and convert to GLfloat */ - _swrast_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, - srcy + row, rgba); - chan_span_to_float(width, (CONST GLchan (*)[4]) rgba, - (GLfloat (*)[4]) dest); - } - - if (changeBuffer) { - /* restore default src/dst buffer */ - _swrast_use_draw_buffer(ctx); + _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, + width, srcx, srcy + row, GL_FLOAT, dest); + dest += 4 * width; } /* do the image transfer ops which preceed convolution */ @@ -214,7 +151,7 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, ASSERT(ctx->Pixel.Separable2DEnabled); _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); } - FREE(tmpImage); + _mesa_free(tmpImage); /* do remaining post-convolution image transfer ops */ for (row = 0; row < height; row++) { @@ -224,82 +161,62 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, width, rgba); } - /* write the new image */ - for (row = 0; row < height; row++) { - const GLfloat *src = convImage + row * width * 4; - GLint dy; - - /* convert floats back to chan */ - float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba); - - if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { - span.end = width; - _swrast_pixel_texture(ctx, &span); - } + if (!sink) { + /* write the new image */ + for (row = 0; row < height; row++) { + const GLfloat *src = convImage + row * width * 4; + GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0]; - /* write row to framebuffer */ + /* copy convolved colors into span array */ + _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat)); - dy = desty + row; - if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { - (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, - (const GLchan (*)[4])span.array->rgba, NULL ); - } - else if (zoom) { - span.x = destx; - span.y = dy; - span.end = width; - _swrast_write_zoomed_rgba_span(ctx, &span, - (CONST GLchan (*)[4])span.array->rgba, - desty, 0); - } - else { + /* write span */ span.x = destx; - span.y = dy; + span.y = desty + row; span.end = width; - _swrast_write_rgba_span(ctx, &span); + span.array->ChanType = GL_FLOAT; + if (zoom) { + _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); + } + else { + _swrast_write_rgba_span(ctx, &span); + } } + /* restore this */ + span.array->ChanType = CHAN_TYPE; } - FREE(convImage); + _mesa_free(convImage); } -/* +/** * RGBA copypixels */ static void copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLchan *tmpImage,*p; - GLboolean quick_draw; - GLint sy, dy, stepy, j; - GLboolean changeBuffer; + GLfloat *tmpImage, *p; + GLint sy, dy, stepy, row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; - const GLuint transferOps = ctx->_ImageTransferState; - struct sw_span span; + GLuint transferOps = ctx->_ImageTransferState; + SWspan span; - INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); + if (!ctx->ReadBuffer->_ColorReadBuffer) { + /* no readbuffer - OK */ + return; + } if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); return; } - - /* Determine if copy should be done bottom-to-top or top-to-bottom */ - if (srcy < desty) { - /* top-down max-to-min */ - sy = srcy + height - 1; - dy = desty + height - 1; - stepy = -1; - } - else { - /* bottom-up min-to-max */ - sy = srcy; - dy = desty; - stepy = 1; + else if (ctx->Pixel.Convolution1DEnabled) { + /* make sure we don't apply 1D convolution */ + transferOps &= ~(IMAGE_CONVOLUTION_BIT | + IMAGE_POST_CONVOLUTION_SCALE_BIAS); } if (ctx->DrawBuffer == ctx->ReadBuffer) { @@ -310,115 +227,84 @@ copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, overlapping = GL_FALSE; } - if (ctx->Depth.Test) - _swrast_span_default_z(ctx, &span); - if (ctx->Fog.Enabled) - _swrast_span_default_fog(ctx, &span); - - if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 - && !zoom - && destx >= 0 - && destx + width <= (GLint) ctx->DrawBuffer->Width) { - quick_draw = GL_TRUE; + /* Determine if copy should be done bottom-to-top or top-to-bottom */ + if (!overlapping && srcy < desty) { + /* top-down max-to-min */ + sy = srcy + height - 1; + dy = desty + height - 1; + stepy = -1; } else { - quick_draw = GL_FALSE; + /* bottom-up min-to-max */ + sy = srcy; + dy = desty; + stepy = 1; } - /* If read and draw buffer are different we must do buffer switching */ - changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] - || ctx->DrawBuffer != ctx->ReadBuffer; + INIT_SPAN(span, GL_BITMAP); + _swrast_span_default_attribs(ctx, &span); + span.arrayMask = SPAN_RGBA; + span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */ if (overlapping) { - GLint ssy = sy; - tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); + tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } - /* setup source */ - if (changeBuffer) - _swrast_use_read_buffer(ctx); - /* read the source image */ + /* read the source image as RGBA/float */ p = tmpImage; - for (j = 0; j < height; j++, ssy += stepy) { - _swrast_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy, - (GLchan (*)[4]) p ); + for (row = 0; row < height; row++) { + _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, + width, srcx, sy + row, GL_FLOAT, p ); p += width * 4; } p = tmpImage; - /* restore dest */ - if (changeBuffer) { - _swrast_use_draw_buffer(ctx); - changeBuffer = GL_FALSE; - } } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } - for (j = 0; j < height; j++, sy += stepy, dy += stepy) { - /* Get source pixels */ + ASSERT(width < MAX_WIDTH); + + for (row = 0; row < height; row++, sy += stepy, dy += stepy) { + GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0]; + + /* Get row/span of source pixels */ if (overlapping) { /* get from buffered image */ - ASSERT(width < MAX_WIDTH); - MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4); + _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4); p += width * 4; } else { /* get from framebuffer */ - if (changeBuffer) - _swrast_use_read_buffer(ctx); - ASSERT(width < MAX_WIDTH); - _swrast_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, - span.array->rgba ); - if (changeBuffer) - _swrast_use_draw_buffer(ctx); + _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, + width, srcx, sy, GL_FLOAT, rgba ); } if (transferOps) { - DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */ - CHECKARRAY(rgbaFloat, return); - - /* convert to float, transfer, convert back to chan */ - chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba, - rgbaFloat); - _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat); - float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat, - span.array->rgba); - - UNDEFARRAY(rgbaFloat); /* mac 32k limitation */ - } - - if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { - span.end = width; - _swrast_pixel_texture(ctx, &span); + _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, + (GLfloat (*)[4]) rgba); } /* Write color span */ - if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { - (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, - (const GLchan (*)[4])span.array->rgba, NULL ); - } - else if (zoom) { - span.x = destx; - span.y = dy; - span.end = width; - _swrast_write_zoomed_rgba_span(ctx, &span, - (CONST GLchan (*)[4]) span.array->rgba, - desty, 0); + span.x = destx; + span.y = dy; + span.end = width; + span.array->ChanType = GL_FLOAT; + if (zoom) { + _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); } else { - span.x = destx; - span.y = dy; - span.end = width; _swrast_write_rgba_span(ctx, &span); } } + span.array->ChanType = CHAN_TYPE; /* restore */ + if (overlapping) - FREE(tmpImage); + _mesa_free(tmpImage); } @@ -430,16 +316,29 @@ copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLuint *tmpImage,*p; GLint sy, dy, stepy; GLint j; - GLboolean changeBuffer; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; - const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; GLint overlapping; - struct sw_span span; + SWspan span; - INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); + if (!ctx->ReadBuffer->_ColorReadBuffer) { + /* no readbuffer - OK */ + return; + } + + INIT_SPAN(span, GL_BITMAP); + _swrast_span_default_attribs(ctx, &span); + span.arrayMask = SPAN_INDEX; + + if (ctx->DrawBuffer == ctx->ReadBuffer) { + overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); + } + else { + overlapping = GL_FALSE; + } /* Determine if copy should be bottom-to-top or top-to-bottom */ - if (srcyDrawBuffer == ctx->ReadBuffer) { - overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, - ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); - } - else { - overlapping = GL_FALSE; - } - - if (ctx->Depth.Test) - _swrast_span_default_z(ctx, &span); - if (ctx->Fog.Enabled) - _swrast_span_default_fog(ctx, &span); - - /* If read and draw buffer are different we must do buffer switching */ - changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] - || ctx->DrawBuffer != ctx->ReadBuffer; - if (overlapping) { GLint ssy = sy; - tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); + tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } - /* setup source */ - if (changeBuffer) - _swrast_use_read_buffer(ctx); /* read the image */ p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { - _swrast_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p ); + _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, + width, srcx, ssy, p ); p += width; } p = tmpImage; - /* restore to draw buffer */ - if (changeBuffer) { - _swrast_use_draw_buffer(ctx); - changeBuffer = GL_FALSE; - } } else { tmpImage = NULL; /* silence compiler warning */ @@ -500,38 +375,65 @@ copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get color indexes */ if (overlapping) { - MEMCPY(span.array->index, p, width * sizeof(GLuint)); + _mesa_memcpy(span.array->index, p, width * sizeof(GLuint)); p += width; } else { - if (changeBuffer) - _swrast_use_read_buffer(ctx); - _swrast_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, - span.array->index ); - if (changeBuffer) - _swrast_use_draw_buffer(ctx); + _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, + width, srcx, sy, span.array->index ); } - /* Apply shift, offset, look-up table */ - if (shift_or_offset) { - _mesa_shift_and_offset_ci( ctx, width, span.array->index ); - } - if (ctx->Pixel.MapColorFlag) { - _mesa_map_ci( ctx, width, span.array->index ); - } + if (ctx->_ImageTransferState) + _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState, + width, span.array->index); /* write color indexes */ span.x = destx; span.y = dy; span.end = width; if (zoom) - _swrast_write_zoomed_index_span(ctx, &span, desty, 0); + _swrast_write_zoomed_index_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } if (overlapping) - FREE(tmpImage); + _mesa_free(tmpImage); +} + + +/** + * Convert floating point Z values to integer Z values with pixel transfer's + * Z scale and bias. + */ +static void +scale_and_bias_z(GLcontext *ctx, GLuint width, + const GLfloat depth[], GLuint z[]) +{ + const GLuint depthMax = ctx->DrawBuffer->_DepthMax; + GLuint i; + + if (depthMax <= 0xffffff && + ctx->Pixel.DepthScale == 1.0 && + ctx->Pixel.DepthBias == 0.0) { + /* no scale or bias and no clamping and no worry of overflow */ + const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF; + for (i = 0; i < width; i++) { + z[i] = (GLuint) (depth[i] * depthMaxF); + } + } + else { + /* need to be careful with overflow */ + const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF; + for (i = 0; i < width; i++) { + GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; + d = CLAMP(d, 0.0, 1.0) * depthMaxF; + if (d >= depthMaxF) + z[i] = depthMax; + else + z[i] = (GLuint) d; + } + } } @@ -544,22 +446,34 @@ copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *readRb = fb->_DepthBuffer; GLfloat *p, *tmpImage; GLint sy, dy, stepy; - GLint i, j; + GLint j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; - struct sw_span span; - - INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); + SWspan span; - if (!ctx->Visual.depthBits) { - _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); + if (!readRb) { + /* no readbuffer - OK */ return; } + INIT_SPAN(span, GL_BITMAP); + _swrast_span_default_attribs(ctx, &span); + span.arrayMask = SPAN_Z; + + if (ctx->DrawBuffer == ctx->ReadBuffer) { + overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); + } + else { + overlapping = GL_FALSE; + } + /* Determine if copy should be bottom-to-top or top-to-bottom */ - if (srcyDrawBuffer == ctx->ReadBuffer) { - overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, - ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); - } - else { - overlapping = GL_FALSE; - } - - _swrast_span_default_color(ctx, &span); - if (ctx->Fog.Enabled) - _swrast_span_default_fog(ctx, &span); - if (overlapping) { GLint ssy = sy; - tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); + tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { - _swrast_read_depth_span_float(ctx, width, srcx, ssy, p); + _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); p += width; } p = tmpImage; @@ -605,43 +507,38 @@ copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, for (j = 0; j < height; j++, sy += stepy, dy += stepy) { GLfloat depth[MAX_WIDTH]; - /* get depth values */ if (overlapping) { - MEMCPY(depth, p, width * sizeof(GLfloat)); + _mesa_memcpy(depth, p, width * sizeof(GLfloat)); p += width; } else { - _swrast_read_depth_span_float(ctx, width, srcx, sy, depth); + _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); } /* apply scale and bias */ - for (i = 0; i < width; i++) { - GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; - span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax); - } + scale_and_bias_z(ctx, width, depth, span.array->z); /* write depth values */ span.x = destx; span.y = dy; span.end = width; - if (ctx->Visual.rgbMode) { + if (fb->Visual.rgbMode) { if (zoom) - _swrast_write_zoomed_rgba_span( ctx, &span, - (const GLchan (*)[4])span.array->rgba, desty, 0 ); + _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); else _swrast_write_rgba_span(ctx, &span); } else { if (zoom) - _swrast_write_zoomed_index_span( ctx, &span, desty, 0 ); + _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } } if (overlapping) - FREE(tmpImage); + _mesa_free(tmpImage); } @@ -651,20 +548,29 @@ copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; GLint sy, dy, stepy; GLint j; GLstencil *p, *tmpImage; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; - const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; GLint overlapping; - if (!ctx->Visual.stencilBits) { - _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); + if (!rb) { + /* no readbuffer - OK */ return; } + if (ctx->DrawBuffer == ctx->ReadBuffer) { + overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); + } + else { + overlapping = GL_FALSE; + } + /* Determine if copy should be bottom-to-top or top-to-bottom */ - if (srcy < desty) { + if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; @@ -677,24 +583,16 @@ copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, stepy = 1; } - if (ctx->DrawBuffer == ctx->ReadBuffer) { - overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, - ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); - } - else { - overlapping = GL_FALSE; - } - if (overlapping) { GLint ssy = sy; - tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil)); + tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { - _swrast_read_stencil_span( ctx, width, srcx, ssy, p ); + _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); p += width; } p = tmpImage; @@ -709,25 +607,19 @@ copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, /* Get stencil values */ if (overlapping) { - MEMCPY(stencil, p, width * sizeof(GLstencil)); + _mesa_memcpy(stencil, p, width * sizeof(GLstencil)); p += width; } else { - _swrast_read_stencil_span( ctx, width, srcx, sy, stencil ); + _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); } - /* Apply shift, offset, look-up table */ - if (shift_or_offset) { - _mesa_shift_and_offset_stencil( ctx, width, stencil ); - } - if (ctx->Pixel.MapStencilFlag) { - _mesa_map_stencil( ctx, width, stencil ); - } + _mesa_apply_stencil_transfer_ops(ctx, width, stencil); /* Write stencil values */ if (zoom) { - _swrast_write_zoomed_stencil_span( ctx, width, destx, dy, - stencil, desty, 0 ); + _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, + destx, dy, stencil); } else { _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); @@ -735,16 +627,276 @@ copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, } if (overlapping) - FREE(tmpImage); + _mesa_free(tmpImage); } +/** + * This isn't terribly efficient. If a driver really has combined + * depth/stencil buffers the driver should implement an optimized + * CopyPixels function. + */ +static void +copy_depth_stencil_pixels(GLcontext *ctx, + const GLint srcX, const GLint srcY, + const GLint width, const GLint height, + const GLint destX, const GLint destY) +{ + struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb; + GLint sy, dy, stepy; + GLint j; + GLstencil *tempStencilImage = NULL, *stencilPtr = NULL; + GLfloat *tempDepthImage = NULL, *depthPtr = NULL; + const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF; + const GLuint stencilMask = ctx->Stencil.WriteMask[0]; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; + const GLboolean scaleOrBias + = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + GLint overlapping; + + depthDrawRb = ctx->DrawBuffer->_DepthBuffer; + depthReadRb = ctx->ReadBuffer->_DepthBuffer; + stencilReadRb = ctx->ReadBuffer->_StencilBuffer; + + ASSERT(depthDrawRb); + ASSERT(depthReadRb); + ASSERT(stencilReadRb); + if (ctx->DrawBuffer == ctx->ReadBuffer) { + overlapping = regions_overlap(srcX, srcY, destX, destY, width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); + } + else { + overlapping = GL_FALSE; + } + + /* Determine if copy should be bottom-to-top or top-to-bottom */ + if (!overlapping && srcY < destY) { + /* top-down max-to-min */ + sy = srcY + height - 1; + dy = destY + height - 1; + stepy = -1; + } + else { + /* bottom-up min-to-max */ + sy = srcY; + dy = destY; + stepy = 1; + } + + if (overlapping) { + GLint ssy = sy; + + if (stencilMask != 0x0) { + tempStencilImage + = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); + if (!tempStencilImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); + return; + } + + /* get copy of stencil pixels */ + stencilPtr = tempStencilImage; + for (j = 0; j < height; j++, ssy += stepy) { + _swrast_read_stencil_span(ctx, stencilReadRb, + width, srcX, ssy, stencilPtr); + stencilPtr += width; + } + stencilPtr = tempStencilImage; + } + + if (ctx->Depth.Mask) { + tempDepthImage + = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); + if (!tempDepthImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); + _mesa_free(tempStencilImage); + return; + } + + /* get copy of depth pixels */ + depthPtr = tempDepthImage; + for (j = 0; j < height; j++, ssy += stepy) { + _swrast_read_depth_span_float(ctx, depthReadRb, + width, srcX, ssy, depthPtr); + depthPtr += width; + } + depthPtr = tempDepthImage; + } + } + + for (j = 0; j < height; j++, sy += stepy, dy += stepy) { + if (stencilMask != 0x0) { + GLstencil stencil[MAX_WIDTH]; + + /* Get stencil values */ + if (overlapping) { + _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil)); + stencilPtr += width; + } + else { + _swrast_read_stencil_span(ctx, stencilReadRb, + width, srcX, sy, stencil); + } + + _mesa_apply_stencil_transfer_ops(ctx, width, stencil); + + /* Write values */ + if (zoom) { + _swrast_write_zoomed_stencil_span(ctx, destX, destY, width, + destX, dy, stencil); + } + else { + _swrast_write_stencil_span( ctx, width, destX, dy, stencil ); + } + } + + if (ctx->Depth.Mask) { + GLfloat depth[MAX_WIDTH]; + GLuint zVals32[MAX_WIDTH]; + GLushort zVals16[MAX_WIDTH]; + GLvoid *zVals; + GLuint zBytes; + + /* get depth values */ + if (overlapping) { + _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat)); + depthPtr += width; + } + else { + _swrast_read_depth_span_float(ctx, depthReadRb, + width, srcX, sy, depth); + } + + /* scale & bias */ + if (scaleOrBias) { + _mesa_scale_and_bias_depth(ctx, width, depth); + } + /* convert to integer Z values */ + if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) { + GLint k; + for (k = 0; k < width; k++) + zVals16[k] = (GLushort) (depth[k] * depthScale); + zVals = zVals16; + zBytes = 2; + } + else { + GLint k; + for (k = 0; k < width; k++) + zVals32[k] = (GLuint) (depth[k] * depthScale); + zVals = zVals32; + zBytes = 4; + } + + /* Write values */ + if (zoom) { + _swrast_write_zoomed_z_span(ctx, destX, destY, width, + destX, dy, zVals); + } + else { + _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes); + } + } + } + + if (tempStencilImage) + _mesa_free(tempStencilImage); + + if (tempDepthImage) + _mesa_free(tempDepthImage); +} + + + +/** + * Try to do a fast copy pixels. + */ +static GLboolean +fast_copy_pixels(GLcontext *ctx, + GLint srcX, GLint srcY, GLsizei width, GLsizei height, + GLint dstX, GLint dstY, GLenum type) +{ + struct gl_framebuffer *srcFb = ctx->ReadBuffer; + struct gl_framebuffer *dstFb = ctx->DrawBuffer; + struct gl_renderbuffer *srcRb, *dstRb; + GLint row, yStep; + + if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 || + ctx->Pixel.ZoomX != 1.0F || + ctx->Pixel.ZoomY != 1.0F || + ctx->_ImageTransferState) { + /* can't handle these */ + return GL_FALSE; + } + + if (type == GL_COLOR) { + if (dstFb->_NumColorDrawBuffers != 1) + return GL_FALSE; + srcRb = srcFb->_ColorReadBuffer; + dstRb = dstFb->_ColorDrawBuffers[0]; + } + else if (type == GL_STENCIL) { + srcRb = srcFb->_StencilBuffer; + dstRb = dstFb->_StencilBuffer; + } + else if (type == GL_DEPTH) { + srcRb = srcFb->_DepthBuffer; + dstRb = dstFb->_DepthBuffer; + } + else { + ASSERT(type == GL_DEPTH_STENCIL_EXT); + /* XXX correct? */ + srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer; + dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer; + } + + /* src and dst renderbuffers must be same format and type */ + if (!srcRb || !dstRb || + srcRb->DataType != dstRb->DataType || + srcRb->_BaseFormat != dstRb->_BaseFormat) { + return GL_FALSE; + } + + /* clipping not supported */ + if (srcX < 0 || srcX + width > (GLint) srcFb->Width || + srcY < 0 || srcY + height > (GLint) srcFb->Height || + dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax || + dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) { + return GL_FALSE; + } + + /* overlapping src/dst doesn't matter, just determine Y direction */ + if (srcY < dstY) { + /* top-down max-to-min */ + srcY = srcY + height - 1; + dstY = dstY + height - 1; + yStep = -1; + } + else { + /* bottom-up min-to-max */ + yStep = 1; + } + + for (row = 0; row < height; row++) { + GLuint temp[MAX_WIDTH][4]; + srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp); + dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL); + srcY += yStep; + dstY += yStep; + } + + return GL_TRUE; +} + + +/** + * Do software-based glCopyPixels. + * By time we get here, all parameters will have been error-checked. + */ void _swrast_CopyPixels( GLcontext *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, - GLint destx, GLint desty, - GLenum type ) + GLint destx, GLint desty, GLenum type ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); RENDER_START(swrast,ctx); @@ -752,20 +904,28 @@ _swrast_CopyPixels( GLcontext *ctx, if (swrast->NewState) _swrast_validate_derived( ctx ); - if (type == GL_COLOR && ctx->Visual.rgbMode) { - copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); - } - else if (type == GL_COLOR && !ctx->Visual.rgbMode) { - copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); - } - else if (type == GL_DEPTH) { - copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); - } - else if (type == GL_STENCIL) { - copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); - } - else { - _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); + if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) { + switch (type) { + case GL_COLOR: + if (ctx->Visual.rgbMode) { + copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); + } + else { + copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); + } + break; + case GL_DEPTH: + copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); + break; + case GL_STENCIL: + copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); + break; + case GL_DEPTH_STENCIL_EXT: + copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty); + break; + default: + _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels"); + } } RENDER_FINISH(swrast,ctx);