/* * To draw a wide line we can simply redraw the span N times, side by side. */ static void draw_wide_line( GLcontext *ctx, SWspan *span, GLboolean xMajor ) { const GLint width = (GLint) CLAMP(ctx->Line.Width, ctx->Const.MinLineWidth, ctx->Const.MaxLineWidth); GLint start; ASSERT(span->end < MAX_WIDTH); if (width & 1) start = width / 2; else start = width / 2 - 1; if (xMajor) { GLint *y = span->array->y; GLuint i; GLint w; for (w = 0; w < width; w++) { if (w == 0) { for (i = 0; i < span->end; i++) y[i] -= start; } else { for (i = 0; i < span->end; i++) y[i]++; } if (ctx->Visual.rgbMode) _swrast_write_rgba_span(ctx, span); else _swrast_write_index_span(ctx, span); } } else { GLint *x = span->array->x; GLuint i; GLint w; for (w = 0; w < width; w++) { if (w == 0) { for (i = 0; i < span->end; i++) x[i] -= start; } else { for (i = 0; i < span->end; i++) x[i]++; } if (ctx->Visual.rgbMode) _swrast_write_rgba_span(ctx, span); else _swrast_write_index_span(ctx, span); } } }
/* * To draw a wide line we can simply redraw the span N times, side by side. */ static void draw_wide_line( struct gl_context *ctx, SWspan *span, GLboolean xMajor ) { const GLint width = (GLint) CLAMP(ctx->Line.Width, ctx->Const.MinLineWidth, ctx->Const.MaxLineWidth); GLint start; assert(span->end < SWRAST_MAX_WIDTH); if (width & 1) start = width / 2; else start = width / 2 - 1; if (xMajor) { GLint *y = span->array->y; GLuint i; GLint w; for (w = 0; w < width; w++) { if (w == 0) { for (i = 0; i < span->end; i++) y[i] -= start; } else { for (i = 0; i < span->end; i++) y[i]++; } _swrast_write_rgba_span(ctx, span); } } else { GLint *x = span->array->x; GLuint i; GLint w; for (w = 0; w < width; w++) { if (w == 0) { for (i = 0; i < span->end; i++) x[i] -= start; } else { for (i = 0; i < span->end; i++) x[i]++; } _swrast_write_rgba_span(ctx, span); } } }
/** * Draw size=1, single-pixel point */ static void pixel_point(struct gl_context *ctx, const SWvertex *vert) { SWcontext *swrast = SWRAST_CONTEXT(ctx); /* * Note that unlike the other functions, we put single-pixel points * into a special span array in order to render as many points as * possible with a single _swrast_write_rgba_span() call. */ SWspan *span = &(swrast->PointSpan); GLuint count; CULL_INVALID(vert); /* Span init */ span->interpMask = 0; span->arrayMask = SPAN_XY | SPAN_Z; span->arrayMask |= SPAN_RGBA; /*span->arrayMask |= SPAN_LAMBDA;*/ span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */ /* need these for fragment programs */ span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; /* check if we need to flush */ if (span->end >= MAX_WIDTH || (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) || span->facing != swrast->PointLineFacing) { if (span->end > 0) { _swrast_write_rgba_span(ctx, span); span->end = 0; } } count = span->end; span->facing = swrast->PointLineFacing; /* fragment attributes */ span->array->rgba[count][RCOMP] = vert->color[0]; span->array->rgba[count][GCOMP] = vert->color[1]; span->array->rgba[count][BCOMP] = vert->color[2]; span->array->rgba[count][ACOMP] = vert->color[3]; ATTRIB_LOOP_BEGIN COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]); ATTRIB_LOOP_END /* fragment position */ span->array->x[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][0]; span->array->y[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][1]; span->array->z[count] = (GLint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); span->end = count + 1; ASSERT(span->end <= MAX_WIDTH); }
void _swrast_flush( struct gl_context *ctx ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); /* flush any pending fragments from rendering points */ if (swrast->PointSpan.end > 0) { _swrast_write_rgba_span(ctx, &(swrast->PointSpan)); swrast->PointSpan.end = 0; } }
void _swrast_flush( GLcontext *ctx ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); /* flush any pending fragments from rendering points */ if (swrast->PointSpan.end > 0) { if (ctx->Visual.rgbMode) { _swrast_write_rgba_span(ctx, &(swrast->PointSpan)); } else { _swrast_write_index_span(ctx, &(swrast->PointSpan)); } swrast->PointSpan.end = 0; } }
/** * Draw a point sprite */ static void sprite_point(GLcontext *ctx, const SWvertex *vert) { SWcontext *swrast = SWRAST_CONTEXT(ctx); SWspan span; GLfloat size; GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1]; GLuint numTcoords = 0; GLfloat t0, dtdy; CULL_INVALID(vert); /* z coord */ if (ctx->DrawBuffer->Visual.depthBits <= 16) span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); else span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); span.zStep = 0; size = get_size(ctx, vert, GL_FALSE); /* span init */ INIT_SPAN(span, GL_POINT); span.interpMask = SPAN_Z | SPAN_RGBA; span.facing = swrast->PointLineFacing; span.red = ChanToFixed(vert->color[0]); span.green = ChanToFixed(vert->color[1]); span.blue = ChanToFixed(vert->color[2]); span.alpha = ChanToFixed(vert->color[3]); span.redStep = 0; span.greenStep = 0; span.blueStep = 0; span.alphaStep = 0; /* need these for fragment programs */ span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; { GLfloat s, r, dsdx; /* texcoord / pointcoord interpolants */ s = 0.0; dsdx = 1.0 / size; if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) { dtdy = 1.0 / size; t0 = 0.5 * dtdy; } else { /* GL_UPPER_LEFT */ dtdy = -1.0 / size; t0 = 1.0 + 0.5 * dtdy; } ATTRIB_LOOP_BEGIN if (attr >= FRAG_ATTRIB_TEX0 && attr < FRAG_ATTRIB_VAR0) { const GLuint u = attr - FRAG_ATTRIB_TEX0; /* a texcoord */ if (ctx->Point.CoordReplace[u]) { tCoords[numTcoords++] = attr; if (ctx->Point.SpriteRMode == GL_ZERO) r = 0.0F; else if (ctx->Point.SpriteRMode == GL_S) r = vert->attrib[attr][0]; else /* GL_R */ r = vert->attrib[attr][2]; span.attrStart[attr][0] = s; span.attrStart[attr][1] = 0.0; /* overwritten below */ span.attrStart[attr][2] = r; span.attrStart[attr][3] = 1.0; span.attrStepX[attr][0] = dsdx; span.attrStepX[attr][1] = 0.0; span.attrStepX[attr][2] = 0.0; span.attrStepX[attr][3] = 0.0; span.attrStepY[attr][0] = 0.0; span.attrStepY[attr][1] = dtdy; span.attrStepY[attr][2] = 0.0; span.attrStepY[attr][3] = 0.0; continue; } } else if (attr == FRAG_ATTRIB_FOGC) { /* GLSL gl_PointCoord is stored in fog.zw */ span.attrStart[FRAG_ATTRIB_FOGC][2] = 0.0; span.attrStart[FRAG_ATTRIB_FOGC][3] = 0.0; /* t0 set below */ span.attrStepX[FRAG_ATTRIB_FOGC][2] = dsdx; span.attrStepX[FRAG_ATTRIB_FOGC][3] = 0.0; span.attrStepY[FRAG_ATTRIB_FOGC][2] = 0.0; span.attrStepY[FRAG_ATTRIB_FOGC][3] = dtdy; tCoords[numTcoords++] = FRAG_ATTRIB_FOGC; continue; } /* use vertex's texcoord/attrib */ COPY_4V(span.attrStart[attr], vert->attrib[attr]); ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); ATTRIB_LOOP_END; } /* compute pos, bounds and render */ { const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; GLint iSize = (GLint) (size + 0.5F); GLint xmin, xmax, ymin, ymax, iy; GLint iRadius; GLfloat tcoord = t0; iSize = MAX2(1, iSize); iRadius = iSize / 2; if (iSize & 1) { /* odd size */ xmin = (GLint) (x - iRadius); xmax = (GLint) (x + iRadius); ymin = (GLint) (y - iRadius); ymax = (GLint) (y + iRadius); } else { /* even size */ /* 0.501 factor allows conformance to pass */ xmin = (GLint) (x + 0.501) - iRadius; xmax = xmin + iSize - 1; ymin = (GLint) (y + 0.501) - iRadius; ymax = ymin + iSize - 1; } /* render spans */ for (iy = ymin; iy <= ymax; iy++) { GLuint i; /* setup texcoord T for this row */ for (i = 0; i < numTcoords; i++) { if (tCoords[i] == FRAG_ATTRIB_FOGC) span.attrStart[FRAG_ATTRIB_FOGC][3] = tcoord; else span.attrStart[tCoords[i]][1] = tcoord; } /* these might get changed by span clipping */ span.x = xmin; span.y = iy; span.end = xmax - xmin + 1; _swrast_write_rgba_span(ctx, &span); tcoord += dtdy; } } }
/** * Draw large (size >= 1) non-AA point. RGB or CI mode. */ static void large_point(GLcontext *ctx, const SWvertex *vert) { SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLboolean ciMode = !ctx->Visual.rgbMode; SWspan span; GLfloat size; CULL_INVALID(vert); /* z coord */ if (ctx->DrawBuffer->Visual.depthBits <= 16) span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); else span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); span.zStep = 0; size = get_size(ctx, vert, GL_FALSE); /* span init */ INIT_SPAN(span, GL_POINT); span.arrayMask = SPAN_XY; span.facing = swrast->PointLineFacing; if (ciMode) { span.interpMask = SPAN_Z | SPAN_INDEX; span.index = FloatToFixed(vert->attrib[FRAG_ATTRIB_CI][0]); span.indexStep = 0; } else { span.interpMask = SPAN_Z | SPAN_RGBA; span.red = ChanToFixed(vert->color[0]); span.green = ChanToFixed(vert->color[1]); span.blue = ChanToFixed(vert->color[2]); span.alpha = ChanToFixed(vert->color[3]); span.redStep = 0; span.greenStep = 0; span.blueStep = 0; span.alphaStep = 0; } /* need these for fragment programs */ span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; ATTRIB_LOOP_BEGIN COPY_4V(span.attrStart[attr], vert->attrib[attr]); ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); ATTRIB_LOOP_END /* compute pos, bounds and render */ { const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; GLint iSize = (GLint) (size + 0.5F); GLint xmin, xmax, ymin, ymax, ix, iy; GLint iRadius; iSize = MAX2(1, iSize); iRadius = iSize / 2; if (iSize & 1) { /* odd size */ xmin = (GLint) (x - iRadius); xmax = (GLint) (x + iRadius); ymin = (GLint) (y - iRadius); ymax = (GLint) (y + iRadius); } else { /* even size */ /* 0.501 factor allows conformance to pass */ xmin = (GLint) (x + 0.501) - iRadius; xmax = xmin + iSize - 1; ymin = (GLint) (y + 0.501) - iRadius; ymax = ymin + iSize - 1; } /* generate fragments */ span.end = 0; for (iy = ymin; iy <= ymax; iy++) { for (ix = xmin; ix <= xmax; ix++) { span.array->x[span.end] = ix; span.array->y[span.end] = iy; span.end++; } } assert(span.end <= MAX_WIDTH); _swrast_write_rgba_span(ctx, &span); } }
/** * Draw smooth/antialiased point. RGB or CI mode. */ static void smooth_point(GLcontext *ctx, const SWvertex *vert) { SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLboolean ciMode = !ctx->Visual.rgbMode; SWspan span; GLfloat size, alphaAtten; CULL_INVALID(vert); /* z coord */ if (ctx->DrawBuffer->Visual.depthBits <= 16) span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); else span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); span.zStep = 0; size = get_size(ctx, vert, GL_TRUE); /* alpha attenuation / fade factor */ if (ctx->Multisample._Enabled) { if (vert->pointSize >= ctx->Point.Threshold) { alphaAtten = 1.0F; } else { GLfloat dsize = vert->pointSize / ctx->Point.Threshold; alphaAtten = dsize * dsize; } } else { alphaAtten = 1.0; } (void) alphaAtten; /* not used */ /* span init */ INIT_SPAN(span, GL_POINT); span.interpMask = SPAN_Z | SPAN_RGBA; span.arrayMask = SPAN_COVERAGE | SPAN_MASK; span.facing = swrast->PointLineFacing; span.red = ChanToFixed(vert->color[0]); span.green = ChanToFixed(vert->color[1]); span.blue = ChanToFixed(vert->color[2]); span.alpha = ChanToFixed(vert->color[3]); span.redStep = 0; span.greenStep = 0; span.blueStep = 0; span.alphaStep = 0; /* need these for fragment programs */ span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; ATTRIB_LOOP_BEGIN COPY_4V(span.attrStart[attr], vert->attrib[attr]); ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); ATTRIB_LOOP_END /* compute pos, bounds and render */ { const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; const GLfloat radius = 0.5F * size; const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */ const GLfloat rmax = radius + 0.7071F; const GLfloat rmin2 = MAX2(0.0F, rmin * rmin); const GLfloat rmax2 = rmax * rmax; const GLfloat cscale = 1.0F / (rmax2 - rmin2); const GLint xmin = (GLint) (x - radius); const GLint xmax = (GLint) (x + radius); const GLint ymin = (GLint) (y - radius); const GLint ymax = (GLint) (y + radius); GLint ix, iy; for (iy = ymin; iy <= ymax; iy++) { /* these might get changed by span clipping */ span.x = xmin; span.y = iy; span.end = xmax - xmin + 1; /* compute coverage for each pixel in span */ for (ix = xmin; ix <= xmax; ix++) { const GLfloat dx = ix - x + 0.5F; const GLfloat dy = iy - y + 0.5F; const GLfloat dist2 = dx * dx + dy * dy; GLfloat coverage; if (dist2 < rmax2) { if (dist2 >= rmin2) { /* compute partial coverage */ coverage = 1.0F - (dist2 - rmin2) * cscale; if (ciMode) { /* coverage in [0,15] */ coverage *= 15.0; } } else { /* full coverage */ coverage = 1.0F; } span.array->mask[ix - xmin] = 1; } else { /* zero coverage - fragment outside the radius */ coverage = 0.0; span.array->mask[ix - xmin] = 0; } span.array->coverage[ix - xmin] = coverage; } /* render span */ _swrast_write_rgba_span(ctx, &span); } } }
/* * Draw depth image. */ static void draw_depth_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 scaleOrBias = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; SWspan span; INIT_SPAN(span, GL_BITMAP); span.arrayMask = SPAN_Z; _swrast_span_default_attribs(ctx, &span); if (type == GL_UNSIGNED_SHORT && ctx->DrawBuffer->Visual.depthBits == 16 && !scaleOrBias && !zoom && width <= SWRAST_MAX_WIDTH && !unpack->SwapBytes) { /* Special case: directly write 16-bit depth values */ GLint row; for (row = 0; row < height; row++) { const GLushort *zSrc = (const GLushort *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); GLint i; for (i = 0; i < width; i++) span.array->z[i] = zSrc[i]; span.x = x; span.y = y + row; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else if (type == GL_UNSIGNED_INT && !scaleOrBias && !zoom && width <= SWRAST_MAX_WIDTH && !unpack->SwapBytes) { /* Special case: shift 32-bit values down to Visual.depthBits */ const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits; GLint row; for (row = 0; row < height; row++) { const GLuint *zSrc = (const GLuint *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); if (shift == 0) { memcpy(span.array->z, zSrc, width * sizeof(GLuint)); } else { GLint col; for (col = 0; col < width; col++) span.array->z[col] = zSrc[col] >> shift; } span.x = x; span.y = y + row; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else {
/* * Draw depth image. */ static void draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; const GLint desty = y; struct sw_span span; INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); 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) { _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); return; } _swrast_span_default_color(ctx, &span); if (ctx->Fog.Enabled) _swrast_span_default_fog(ctx, &span); if (ctx->Texture._EnabledCoordUnits) _swrast_span_default_texcoords(ctx, &span); if (type == GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16 && !bias_or_scale && !zoom && ctx->Visual.rgbMode && width <= MAX_WIDTH) { /* Special case: directly write 16-bit depth values */ GLint row, spanY = y; for (row = 0; row < height; row++, spanY++) { const GLushort *zSrc = (const GLushort *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); GLint i; for (i = 0; i < width; i++) span.array->z[i] = zSrc[i]; span.x = x; span.y = spanY; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else if (type == GL_UNSIGNED_INT && sizeof(GLdepth) == 4 && !bias_or_scale && !zoom && ctx->Visual.rgbMode && width <= MAX_WIDTH) { /* Special case: shift 32-bit values down to ctx->Visual.depthBits */ const GLint shift = 32 - ctx->Visual.depthBits; GLint row, spanY = y; for (row = 0; row < height; row++, spanY++) { const GLuint *zSrc = (const GLuint *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); if (shift == 0) { MEMCPY(span.array->z, zSrc, width * sizeof(GLdepth)); } else { GLint col; for (col = 0; col < width; col++) span.array->z[col] = zSrc[col] >> shift; } span.x = x; span.y = spanY; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else {
/** * 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); GLint row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLbitfield transferOps = ctx->_ImageTransferState; const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink); GLfloat *dest, *tmpImage, *convImage; SWspan span; INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); _swrast_span_default_secondary_color(ctx, &span); /* allocate space for GLfloat image */ tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!tmpImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!convImage) { _mesa_free(tmpImage); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } /* read source image as float/RGBA */ dest = tmpImage; for (row = 0; row < height; row++) { _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 */ for (row = 0; row < height; row++) { GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); _mesa_apply_rgba_transfer_ops(ctx, transferOps & IMAGE_PRE_CONVOLUTION_BITS, width, rgba); } /* do convolution */ if (ctx->Pixel.Convolution2DEnabled) { _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); } else { ASSERT(ctx->Pixel.Separable2DEnabled); _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); } _mesa_free(tmpImage); /* do remaining post-convolution image transfer ops */ for (row = 0; row < height; row++) { GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); _mesa_apply_rgba_transfer_ops(ctx, transferOps & IMAGE_POST_CONVOLUTION_BITS, width, rgba); } if (!sink) { /* write the new image */ for (row = 0; row < height; row++) { const GLfloat *src = convImage + row * width * 4; GLvoid *rgba = (GLvoid *) span.array->attribs[FRAG_ATTRIB_COL0]; /* copy convolved colors into span array */ _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat)); /* write span */ span.x = destx; span.y = desty + row; span.end = width; 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; } _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); GLfloat *tmpImage, *p; GLint sy, dy, stepy, row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; GLuint transferOps = ctx->_ImageTransferState; SWspan span; 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; } 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) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* 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 { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); _swrast_span_default_secondary_color(ctx, &span); if (overlapping) { tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image as RGBA/float */ p = tmpImage; 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; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } 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 */ _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4); p += width * 4; } else { /* get from framebuffer */ _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, GL_FLOAT, rgba ); } if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, (GLfloat (*)[4]) rgba); } /* Write color span */ 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 { _swrast_write_rgba_span(ctx, &span); } } span.array->ChanType = CHAN_TYPE; /* restore */ if (overlapping) _mesa_free(tmpImage); }
/* * TODO: Optimize!!!! */ static void 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 j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; SWspan span; 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 (!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 = (GLfloat *) 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, readRb, 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) { GLfloat depth[MAX_WIDTH]; /* get depth values */ if (overlapping) { memcpy(depth, p, width * sizeof(GLfloat)); p += width; } else { _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); } /* apply scale and bias */ scale_and_bias_z(ctx, width, depth, span.array->z); /* write depth values */ span.x = destx; span.y = dy; span.end = width; if (zoom) _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); else _swrast_write_rgba_span(ctx, &span); } if (overlapping) free(tmpImage); }
/* * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span(). */ static void zoom_span( GLcontext *ctx, const struct sw_span *span, const GLvoid *src, GLint y0, GLenum format, GLint skipPixels ) { GLint r0, r1, row; GLint c0, c1, skipCol; GLint i, j; const GLuint maxWidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); struct sw_span zoomed; struct span_arrays zoomed_arrays; /* this is big! */ /* no pixel arrays! must be horizontal spans. */ ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(span->primitive == GL_BITMAP); INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0); zoomed.array = &zoomed_arrays; /* copy fog interp info */ zoomed.fog = span->fog; zoomed.fogStep = span->fogStep; /* XXX copy texcoord info? */ if (format == GL_RGBA || format == GL_RGB) { /* copy Z info */ zoomed.z = span->z; zoomed.zStep = span->zStep; /* we'll generate an array of colorss */ zoomed.interpMask = span->interpMask & ~SPAN_RGBA; zoomed.arrayMask |= SPAN_RGBA; } else if (format == GL_COLOR_INDEX) { /* copy Z info */ zoomed.z = span->z; zoomed.zStep = span->zStep; /* we'll generate an array of color indexes */ zoomed.interpMask = span->interpMask & ~SPAN_INDEX; zoomed.arrayMask |= SPAN_INDEX; } else { assert(format == GL_DEPTH_COMPONENT); /* Copy color info */ zoomed.red = span->red; zoomed.green = span->green; zoomed.blue = span->blue; zoomed.alpha = span->alpha; zoomed.redStep = span->redStep; zoomed.greenStep = span->greenStep; zoomed.blueStep = span->blueStep; zoomed.alphaStep = span->alphaStep; /* we'll generate an array of depth values */ zoomed.interpMask = span->interpMask & ~SPAN_Z; zoomed.arrayMask |= SPAN_Z; } /* * Compute which columns to draw: [c0, c1) */ c0 = (GLint) (span->x + skipPixels * ctx->Pixel.ZoomX); c1 = (GLint) (span->x + (skipPixels + span->end) * ctx->Pixel.ZoomX); if (c0 == c1) { return; } else if (c1 < c0) { /* swap */ GLint ctmp = c1; c1 = c0; c0 = ctmp; } if (c0 < 0) { zoomed.x = 0; zoomed.start = 0; zoomed.end = c1; skipCol = -c0; } else { zoomed.x = c0; zoomed.start = 0; zoomed.end = c1 - c0; skipCol = 0; } if (zoomed.end > maxWidth) zoomed.end = maxWidth; /* * Compute which rows to draw: [r0, r1) */ row = span->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) { /* swap */ GLint rtmp = r1; r1 = r0; r0 = rtmp; } ASSERT(r0 < r1); ASSERT(c0 < c1); /* * Trivial clip rejection testing. */ if (r1 < 0) /* below window */ return; if (r0 >= (GLint) ctx->DrawBuffer->Height) /* above window */ return; if (c1 < 0) /* left of window */ return; if (c0 >= (GLint) ctx->DrawBuffer->Width) /* right of window */ return; /* zoom the span horizontally */ if (format == GL_RGBA) { const GLchan (*rgba)[4] = (const GLchan (*)[4]) src; if (ctx->Pixel.ZoomX == -1.0F) { /* common case */ for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = span->end - (j + skipCol) - 1; COPY_CHAN4(zoomed.array->rgba[j], rgba[i]); } } else { /* general solution */ const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = (GLint) ((j + skipCol) * xscale); if (ctx->Pixel.ZoomX < 0.0) { ASSERT(i <= 0); i = span->end + i - 1; } ASSERT(i >= 0); ASSERT(i < (GLint) span->end); COPY_CHAN4(zoomed.array->rgba[j], rgba[i]); } } } else if (format == GL_RGB) { const GLchan (*rgb)[3] = (const GLchan (*)[3]) src; if (ctx->Pixel.ZoomX == -1.0F) { /* common case */ for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = span->end - (j + skipCol) - 1; zoomed.array->rgba[j][0] = rgb[i][0]; zoomed.array->rgba[j][1] = rgb[i][1]; zoomed.array->rgba[j][2] = rgb[i][2]; zoomed.array->rgba[j][3] = CHAN_MAX; } } else { /* general solution */ const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = (GLint) ((j + skipCol) * xscale); if (ctx->Pixel.ZoomX < 0.0) { ASSERT(i <= 0); i = span->end + i - 1; } ASSERT(i >= 0); ASSERT(i < (GLint) span->end); zoomed.array->rgba[j][0] = rgb[i][0]; zoomed.array->rgba[j][1] = rgb[i][1]; zoomed.array->rgba[j][2] = rgb[i][2]; zoomed.array->rgba[j][3] = CHAN_MAX; } } } else if (format == GL_COLOR_INDEX) { const GLuint *indexes = (const GLuint *) src; if (ctx->Pixel.ZoomX == -1.0F) { /* common case */ for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = span->end - (j + skipCol) - 1; zoomed.array->index[j] = indexes[i]; } } else { /* general solution */ const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = (GLint) ((j + skipCol) * xscale); if (ctx->Pixel.ZoomX < 0.0) { ASSERT(i <= 0); i = span->end + i - 1; } ASSERT(i >= 0); ASSERT(i < (GLint) span->end); zoomed.array->index[j] = indexes[i]; } } } else { const GLdepth *zValues = (const GLuint *) src; assert(format == GL_DEPTH_COMPONENT); if (ctx->Pixel.ZoomX == -1.0F) { /* common case */ for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = span->end - (j + skipCol) - 1; zoomed.array->z[j] = zValues[i]; } } else { /* general solution */ const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { i = (GLint) ((j + skipCol) * xscale); if (ctx->Pixel.ZoomX < 0.0) { ASSERT(i <= 0); i = span->end + i - 1; } ASSERT(i >= 0); ASSERT(i < (GLint) span->end); zoomed.array->z[j] = zValues[i]; } } /* Now, fall into either the RGB or COLOR_INDEX path below */ if (ctx->Visual.rgbMode) format = GL_RGBA; else format = GL_COLOR_INDEX; } /* write the span in rows [r0, r1) */ if (format == GL_RGBA || format == GL_RGB) { /* Writing the span may modify the colors, so make a backup now if we're * going to call _swrast_write_zoomed_span() more than once. * Also, clipping may change the span end value, so store it as well. */ GLchan rgbaSave[MAX_WIDTH][4]; const GLint end = zoomed.end; /* save */ if (r1 - r0 > 1) { MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * 4 * sizeof(GLchan)); } for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) { _swrast_write_rgba_span(ctx, &zoomed); zoomed.end = end; /* restore */ if (r1 - r0 > 1) { /* restore the colors */ MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end*4 * sizeof(GLchan)); } } } else if (format == GL_COLOR_INDEX) { GLuint indexSave[MAX_WIDTH]; const GLint end = zoomed.end; /* save */ if (r1 - r0 > 1) { MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint)); } for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) { _swrast_write_index_span(ctx, &zoomed); zoomed.end = end; /* restore */ if (r1 - r0 > 1) { /* restore the colors */ MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint)); } } } }
/* * XXX this is another way to implement Bitmap. Use horizontal runs of * fragments, initializing the mask array to indicate which fragments to * draw or skip. */ void _swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLint row, col; SWspan span; ASSERT(ctx->RenderMode == GL_RENDER); ASSERT(bitmap); swrast_render_start(ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP); span.end = width; span.arrayMask = SPAN_MASK; _swrast_span_default_attribs(ctx, &span); /*span.arrayMask |= SPAN_MASK;*/ /* we'll init span.mask[] */ span.x = px; span.y = py; /*span.end = width;*/ for (row=0; row<height; row++, span.y++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (unpack->LsbFirst) { /* Lsb first */ GLubyte mask = 1U << (unpack->SkipPixels & 0x7); for (col=0; col<width; col++) { span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; if (mask == 128U) { src++; mask = 1U; } else { mask = mask << 1; } } _swrast_write_rgba_span(ctx, &span); /* get ready for next row */ if (mask != 1) src++; } else { /* Msb first */ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); for (col=0; col<width; col++) { span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; if (mask == 1U) { src++; mask = 128U; } else { mask = mask >> 1; } } _swrast_write_rgba_span(ctx, &span); /* get ready for next row */ if (mask != 128) src++; } } swrast_render_finish(ctx); }
/** * Render a bitmap. * Called via ctx->Driver.Bitmap() * All parameter error checking will have been done before this is called. */ void _swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { GLint row, col; GLuint count = 0; SWspan span; ASSERT(ctx->RenderMode == GL_RENDER); if (!_mesa_check_conditional_render(ctx)) return; /* don't draw */ bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) return; swrast_render_start(ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP); span.end = width; span.arrayMask = SPAN_XY; _swrast_span_default_attribs(ctx, &span); for (row = 0; row < height; row++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (unpack->LsbFirst) { /* Lsb first */ GLubyte mask = 1U << (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 128U) { src++; mask = 1U; } else { mask = mask << 1; } } /* get ready for next row */ if (mask != 1) src++; } else { /* Msb first */ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 1U) { src++; mask = 128U; } else { mask = mask >> 1; } } /* get ready for next row */ if (mask != 128) src++; } if (count + width >= SWRAST_MAX_WIDTH || row + 1 == height) { /* flush the span */ span.end = count; _swrast_write_rgba_span(ctx, &span); span.end = 0; count = 0; } } swrast_render_finish(ctx); _mesa_unmap_pbo_source(ctx, unpack); }
/* * 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); struct gl_renderbuffer *drawRb = NULL; GLboolean quick_draw; GLint row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLuint transferOps = ctx->_ImageTransferState; 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 (swrast->_FogEnabled) _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; drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0]; } else { quick_draw = GL_FALSE; } /* allocate space for GLfloat image */ tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!tmpImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!convImage) { _mesa_free(tmpImage); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } /* read source image */ 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->_ColorReadBuffer, width, srcx, srcy + row, rgba); chan_span_to_float(width, (CONST GLchan (*)[4]) rgba, (GLfloat (*)[4]) dest); dest += 4 * width; } /* do the image transfer ops which preceed convolution */ for (row = 0; row < height; row++) { GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); _mesa_apply_rgba_transfer_ops(ctx, transferOps & IMAGE_PRE_CONVOLUTION_BITS, width, rgba); } /* do convolution */ if (ctx->Pixel.Convolution2DEnabled) { _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); } else { ASSERT(ctx->Pixel.Separable2DEnabled); _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); } _mesa_free(tmpImage); /* do remaining post-convolution image transfer ops */ for (row = 0; row < height; row++) { GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); _mesa_apply_rgba_transfer_ops(ctx, transferOps & IMAGE_POST_CONVOLUTION_BITS, 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); /* write row to framebuffer */ dy = desty + row; if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL); } else { span.x = destx; span.y = dy; span.end = width; if (zoom) { _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, (CONST GLchan (*)[4])span.array->rgba); } else { _swrast_write_rgba_span(ctx, &span); } } } _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); struct gl_renderbuffer *drawRb; GLchan *tmpImage,*p; GLboolean quick_draw; GLint sy, dy, stepy, j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; const GLuint transferOps = ctx->_ImageTransferState; struct sw_span span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 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; } 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 (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _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; drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0]; } else { quick_draw = GL_FALSE; drawRb = NULL; } if (overlapping) { GLint ssy = sy; tmpImage = (GLchan *) _mesa_malloc(width * height * sizeof(GLchan) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image */ p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, ssy, (GLchan (*)[4]) p ); p += width * 4; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get source pixels */ if (overlapping) { /* get from buffered image */ ASSERT(width < MAX_WIDTH); _mesa_memcpy(span.array->rgba, p, width * sizeof(GLchan) * 4); p += width * 4; } else { /* get from framebuffer */ ASSERT(width < MAX_WIDTH); _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, span.array->rgba ); } if (transferOps) { GLfloat rgbaFloat[MAX_WIDTH][4]; /* 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); } /* Write color span */ if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL); } else { span.x = destx; span.y = dy; span.end = width; if (zoom) { _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, (CONST GLchan (*)[4]) span.array->rgba); } else { _swrast_write_rgba_span(ctx, &span); } } } if (overlapping) _mesa_free(tmpImage); }
/* * TODO: Optimize!!!! */ static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *readRb = fb->_DepthBuffer; const GLfloat depthMax = fb->_DepthMaxF; GLfloat *p, *tmpImage; GLint sy, dy, stepy; GLint i, j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; struct sw_span span; if (!readRb) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); /* 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; } _swrast_span_default_color(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); if (overlapping) { GLint ssy = sy; 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, readRb, 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) { GLfloat depth[MAX_WIDTH]; /* get depth values */ if (overlapping) { _mesa_memcpy(depth, p, width * sizeof(GLfloat)); p += width; } else { _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] = (GLuint) (CLAMP(d, 0.0F, 1.0F) * depthMax); } /* write depth values */ span.x = destx; span.y = dy; span.end = width; if (fb->Visual.rgbMode) { if (zoom) _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, (const GLchan (*)[4]) span.array->rgba); else _swrast_write_rgba_span(ctx, &span); } else { if (zoom) _swrast_write_zoomed_index_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } } if (overlapping) _mesa_free(tmpImage); }
/** * Helper function called from _swrast_write_zoomed_rgba/rgb/ * index/depth_span(). */ static void zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span, const GLvoid *src, GLenum format ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); SWspan zoomed; GLint x0, x1, y0, y1; GLint zoomedWidth; if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end, &x0, &x1, &y0, &y1)) { return; /* totally clipped */ } if (!swrast->ZoomedArrays) { /* allocate on demand */ swrast->ZoomedArrays = (SWspanarrays *) CALLOC(sizeof(SWspanarrays)); if (!swrast->ZoomedArrays) return; } zoomedWidth = x1 - x0; ASSERT(zoomedWidth > 0); ASSERT(zoomedWidth <= MAX_WIDTH); /* no pixel arrays! must be horizontal spans. */ ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(span->primitive == GL_BITMAP); INIT_SPAN(zoomed, GL_BITMAP); zoomed.x = x0; zoomed.end = zoomedWidth; zoomed.array = swrast->ZoomedArrays; zoomed.array->ChanType = span->array->ChanType; if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8; else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16; else zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[FRAG_ATTRIB_COL]; COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]); COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]); COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]); zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0]; zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0]; zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0]; if (format == GL_RGBA || format == GL_RGB) { /* copy Z info */ zoomed.z = span->z; zoomed.zStep = span->zStep; /* we'll generate an array of colorss */ zoomed.interpMask = span->interpMask & ~SPAN_RGBA; zoomed.arrayMask |= SPAN_RGBA; zoomed.arrayAttribs |= FRAG_BIT_COL; /* we'll produce these values */ ASSERT(span->arrayMask & SPAN_RGBA); } else if (format == GL_DEPTH_COMPONENT) { /* Copy color info */ zoomed.red = span->red; zoomed.green = span->green; zoomed.blue = span->blue; zoomed.alpha = span->alpha; zoomed.redStep = span->redStep; zoomed.greenStep = span->greenStep; zoomed.blueStep = span->blueStep; zoomed.alphaStep = span->alphaStep; /* we'll generate an array of depth values */ zoomed.interpMask = span->interpMask & ~SPAN_Z; zoomed.arrayMask |= SPAN_Z; ASSERT(span->arrayMask & SPAN_Z); } else { _mesa_problem(ctx, "Bad format in zoom_span"); return; } /* zoom the span horizontally */ if (format == GL_RGBA) { if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < (GLint) span->end); COPY_4UBV(zoomed.array->rgba8[i], rgba[j]); } } else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { const GLushort (*rgba)[4] = (const GLushort (*)[4]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < (GLint) span->end); COPY_4V(zoomed.array->rgba16[i], rgba[j]); } } else { const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < span->end); COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL][i], rgba[j]); } } } else if (format == GL_RGB) { if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < (GLint) span->end); zoomed.array->rgba8[i][0] = rgb[j][0]; zoomed.array->rgba8[i][1] = rgb[j][1]; zoomed.array->rgba8[i][2] = rgb[j][2]; zoomed.array->rgba8[i][3] = 0xff; } } else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { const GLushort (*rgb)[3] = (const GLushort (*)[3]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < (GLint) span->end); zoomed.array->rgba16[i][0] = rgb[j][0]; zoomed.array->rgba16[i][1] = rgb[j][1]; zoomed.array->rgba16[i][2] = rgb[j][2]; zoomed.array->rgba16[i][3] = 0xffff; } } else { const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < span->end); zoomed.array->attribs[FRAG_ATTRIB_COL][i][0] = rgb[j][0]; zoomed.array->attribs[FRAG_ATTRIB_COL][i][1] = rgb[j][1]; zoomed.array->attribs[FRAG_ATTRIB_COL][i][2] = rgb[j][2]; zoomed.array->attribs[FRAG_ATTRIB_COL][i][3] = 1.0F; } } } else if (format == GL_DEPTH_COMPONENT) { const GLuint *zValues = (const GLuint *) src; GLint i; for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; ASSERT(j >= 0); ASSERT(j < (GLint) span->end); zoomed.array->z[i] = zValues[j]; } /* Now, fall into the RGB path below */ format = GL_RGBA; } /* write the span in rows [r0, r1) */ if (format == GL_RGBA || format == GL_RGB) { /* Writing the span may modify the colors, so make a backup now if we're * going to call _swrast_write_zoomed_span() more than once. * Also, clipping may change the span end value, so store it as well. */ const GLint end = zoomed.end; /* save */ void *rgbaSave; const GLint pixelSize = (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) : ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort) : 4 * sizeof(GLfloat)); rgbaSave = malloc(zoomed.end * pixelSize); if (!rgbaSave) { return; } if (y1 - y0 > 1) { memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize); } for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) { _swrast_write_rgba_span(ctx, &zoomed); zoomed.end = end; /* restore */ if (y1 - y0 > 1) { /* restore the colors */ memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize); } } free(rgbaSave); } }
/** * RGBA copypixels */ static void copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { GLfloat *tmpImage, *p; GLint sy, dy, stepy, row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; GLuint transferOps = ctx->_ImageTransferState; SWspan span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* 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 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 { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } INIT_SPAN(span, GL_BITMAP); _swrast_span_default_attribs(ctx, &span); span.arrayMask = SPAN_RGBA; span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */ if (overlapping) { tmpImage = malloc(width * height * sizeof(GLfloat) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image as RGBA/float */ p = tmpImage; for (row = 0; row < height; row++) { _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy + row, p ); p += width * 4; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } ASSERT(width < SWRAST_MAX_WIDTH); for (row = 0; row < height; row++, sy += stepy, dy += stepy) { GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0]; /* Get row/span of source pixels */ if (overlapping) { /* get from buffered image */ memcpy(rgba, p, width * sizeof(GLfloat) * 4); p += width * 4; } else { /* get from framebuffer */ _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, rgba ); } if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, (GLfloat (*)[4]) rgba); } /* Write color span */ 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 { _swrast_write_rgba_span(ctx, &span); } } span.array->ChanType = CHAN_TYPE; /* restore */ if (overlapping) free(tmpImage); }