/** * Zoom/write stencil values. * No per-fragment operations are applied. */ void _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY, GLint width, GLint spanX, GLint spanY, const GLubyte stencil[]) { GLubyte zoomedVals[MAX_WIDTH]; GLint x0, x1, y0, y1, y; GLint i, zoomedWidth; if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, &x0, &x1, &y0, &y1)) { return; /* totally clipped */ } zoomedWidth = x1 - x0; ASSERT(zoomedWidth > 0); ASSERT(zoomedWidth <= MAX_WIDTH); /* zoom the span horizontally */ for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; ASSERT(j >= 0); ASSERT(j < width); zoomedVals[i] = stencil[j]; } /* write the zoomed spans */ for (y = y0; y < y1; y++) { _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals); } }
/* * Draw stencil image. */ static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; GLint skipPixels; /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = x + skipPixels; const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); GLint row; for (row = 0; row < height; row++) { const GLint spanY = y + row; GLstencil values[MAX_WIDTH]; GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, type, source, unpack, ctx->_ImageTransferState); if (zoom) { _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, spanX, spanY, values); } else { _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values); } } skipPixels += spanWidth; } }
/* * Draw stencil image. */ static void draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; const GLenum destType = GL_UNSIGNED_BYTE; GLint row; GLubyte *values; values = malloc(width * sizeof(GLubyte)); if (!values) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); return; } for (row = 0; row < height; row++) { const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_STENCIL_INDEX, type, row, 0); _mesa_unpack_stencil_span(ctx, width, destType, values, type, source, unpack, ctx->_ImageTransferState); if (zoom) { _swrast_write_zoomed_stencil_span(ctx, x, y, width, x, y, values); } else { _swrast_write_stencil_span(ctx, width, x, y, values); } y++; } free(values); }
/** * 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 shiftOrOffset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 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); /* Determine if copy should be 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; } 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; 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); } /* Apply shift, offset, look-up table */ if (shiftOrOffset) { _mesa_shift_and_offset_stencil(ctx, width, stencil); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil(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); }
static void 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 (!rb) { /* no readbuffer - OK */ return; } /* Determine if copy should be 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; } 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 *) _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, rb, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { GLstencil stencil[MAX_WIDTH]; /* Get stencil values */ if (overlapping) { _mesa_memcpy(stencil, p, width * sizeof(GLstencil)); p += width; } else { _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 ); } /* Write stencil 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 (overlapping) _mesa_free(tmpImage); }
/* * Draw stencil image. */ static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; const GLint desty = y; GLint row, skipPixels; if (type != GL_BYTE && type != GL_UNSIGNED_BYTE && type != GL_SHORT && type != GL_UNSIGNED_SHORT && type != GL_INT && type != GL_UNSIGNED_INT && type != GL_FLOAT && type != GL_BITMAP) { _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); return; } if (ctx->Visual.stencilBits == 0) { _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)"); return; } /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = x; GLint spanY = y; const GLint spanWidth = (width - skipPixels > MAX_WIDTH) ? MAX_WIDTH : (width - skipPixels); for (row = 0; row < height; row++, spanY++) { GLstencil values[MAX_WIDTH]; GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_index_span(ctx, spanWidth, destType, values, type, source, unpack, ctx->_ImageTransferState); if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { _mesa_shift_and_offset_stencil(ctx, spanWidth, values); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil(ctx, spanWidth, values); } if (zoom) { _swrast_write_zoomed_stencil_span(ctx, (GLuint) spanWidth, spanX, spanY, values, desty, 0); } else { _swrast_write_stencil_span(ctx, (GLuint) spanWidth, spanX, spanY, values); } } skipPixels += spanWidth; } }
/* * As above, but write stencil values. */ void _swrast_write_zoomed_stencil_span( GLcontext *ctx, GLuint n, GLint x, GLint y, const GLstencil stencil[], GLint y0, GLint skipPixels ) { GLint m; GLint r0, r1, row, r; GLint i, j, skipcol; GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */ GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); (void) skipPixels; /* XXX this shouldn't be ignored */ /* compute width of output row */ m = (GLint) FABSF( n * ctx->Pixel.ZoomX ); if (m==0) { return; } if (ctx->Pixel.ZoomX<0.0) { /* adjust x coordinate for left/right mirroring */ x = x - m; } /* compute which rows to draw */ row = y - y0; r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); if (r0==r1) { return; } else if (r1<r0) { GLint rtmp = r1; r1 = r0; r0 = rtmp; } /* return early if r0...r1 is above or below window */ if (r0<0 && r1<0) { /* below window */ return; } if (r0 >= (GLint) ctx->DrawBuffer->Height && r1 >= (GLint) ctx->DrawBuffer->Height) { /* above window */ return; } /* check if left edge is outside window */ skipcol = 0; if (x<0) { skipcol = -x; m += x; } /* make sure span isn't too long or short */ if (m>maxwidth) { m = maxwidth; } else if (m<=0) { return; } ASSERT( m <= MAX_WIDTH ); /* zoom the span horizontally */ if (ctx->Pixel.ZoomX==-1.0F) { /* n==m */ for (j=0;j<m;j++) { i = n - (j+skipcol) - 1; zstencil[j] = stencil[i]; } } else { GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; for (j=0;j<m;j++) { i = (GLint) ((j+skipcol) * xscale); if (i<0) i = n + i - 1; zstencil[j] = stencil[i]; } } /* write the span */ for (r=r0; r<r1; r++) { _swrast_write_stencil_span( ctx, m, x+skipcol, r, zstencil ); } }
static void copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLint sy, dy, stepy; GLint j; GLubyte *p, *tmpImage, *stencil; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; 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 (!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; tmpImage = malloc(width * height * sizeof(GLubyte)); 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, rb, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } stencil = malloc(width * sizeof(GLubyte)); if (!stencil) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()"); goto end; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get stencil values */ if (overlapping) { memcpy(stencil, p, width * sizeof(GLubyte)); p += width; } else { _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); } _mesa_apply_stencil_transfer_ops(ctx, width, stencil); /* Write stencil 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 ); } } free(stencil); end: if (overlapping) free(tmpImage); }