From 5eba613e22a1096302c46df395f9a6d67f6b8625 Mon Sep 17 00:00:00 2001 From: Daniel J Sebald Date: Sun, 29 Mar 2015 22:52:08 -0500 Subject: [PATCH] swrast: Correct pixel draw span endpoints computation, rid vertical lines Change the start/end indeces computation to use ceiling, not an int cast, of the encompassing rectangle. Solves problem of dropped pixels at GL_MAX_TEXTURE_SIZE/SWRAST_MAX_WIDTH intervals that created vertical lines when -1.0 < xfactor < 1.0. Also fine tune unzoom formula and add a macro SPAN_LOOP_X() for all pixel zoom operations. --- src/mesa/swrast/s_zoom.c | 252 +++++++++++++++++++++++++++++---------------- 1 files changed, 162 insertions(+), 90 deletions(-) diff --git a/src/mesa/swrast/s_zoom.c b/src/mesa/swrast/s_zoom.c index ab22652..067d1d6 100644 --- a/src/mesa/swrast/s_zoom.c +++ b/src/mesa/swrast/s_zoom.c @@ -34,11 +34,36 @@ #include "s_zoom.h" +#define SPAN_LOOP_X(OPERATION) \ + do { \ + if (ctx->Pixel.ZoomX > 0) { \ + GLint i; \ + for (i = 0; i < zoomedWidth; i++) { \ + GLint j = positive_unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; \ + OPERATION; \ + } \ + } \ + else { \ + GLint i; \ + for (i = 0; i < zoomedWidth; i++) { \ + GLint j = negative_unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; \ + OPERATION; \ + } \ + } \ + } while (0) + + +/* These are meant to address numerical effects of xfactor/yfactor being + * single-precision floating point numbers, as opposed to real numbers. + */ +#define EPSFLOOR 0.00004 +#define EPSCEIL 0.00004 + /** * Compute the bounds of the region resulting from zooming a pixel span. * The resulting region will be entirely inside the window/scissor bounds * so no additional clipping is needed. - * \param imageX, imageY position of the mage being drawn (gl WindowPos) + * \param imageX, imageY position of the image being drawn (gl WindowPos) * \param spanX, spanY position of span being drawing * \param width number of pixels in span * \param x0, x1 returned X bounds of zoomed region [x0, x1) @@ -47,7 +72,7 @@ */ static GLboolean compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY, - GLint spanX, GLint spanY, GLint width, + GLint spanX, GLint spanY, GLint spanWidth, GLint *x0, GLint *x1, GLint *y0, GLint *y1) { const struct gl_framebuffer *fb = ctx->DrawBuffer; @@ -58,35 +83,41 @@ compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY, /* * Compute destination columns: [c0, c1) + * + * c0 - Pixels on left rectangle edge and greater are included + * c1 - Pixels on right rectangle edge and greater are excluded */ - c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX); - c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX); - if (c1 < c0) { - /* swap */ + c0 = imageX + (GLint) ceilf((spanX - imageX) * ctx->Pixel.ZoomX - EPSCEIL); + c1 = imageX + (GLint) ceilf((spanX + spanWidth - imageX) * ctx->Pixel.ZoomX - EPSCEIL); + if (ctx->Pixel.ZoomX < 0) { + /* swap edge roles */ GLint tmp = c1; c1 = c0; c0 = tmp; } c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax); c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax); - if (c0 == c1) { + if (c0 >= c1) { return GL_FALSE; /* no width */ } /* * Compute destination rows: [r0, r1) + * + * r0 - Pixels on bottom rectangle edge and greater are included + * r1 - Pixels on top rectangle edge and greater are excluded */ - r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY); - r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY); - if (r1 < r0) { - /* swap */ + r0 = imageY + (GLint) ceilf((spanY - imageY) * ctx->Pixel.ZoomY - EPSCEIL); + r1 = imageY + (GLint) ceilf((spanY + 1 - imageY) * ctx->Pixel.ZoomY - EPSCEIL); + if (ctx->Pixel.ZoomY < 0) { + /* swap edge roles */ GLint tmp = r1; r1 = r0; r0 = tmp; } r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax); r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax); - if (r0 == r1) { + if (r0 >= r1) { return GL_FALSE; /* no height */ } @@ -101,26 +132,106 @@ compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY, /** * Convert a zoomed x image coordinate back to an unzoomed x coord. - * 'zx' is screen position of a pixel in the zoomed image, who's left edge - * is at 'imageX'. - * return corresponding x coord in the original, unzoomed image. - * This can use this for unzooming X or Y values. + * 'xz' is screen position of a pixel in the zoomed image. 'xr' is + * the raster reference of the unzoomed image. + * + * Return corresponding x coord in the original, unzoomed image. + * This can be used for unzooming both X or Y values. */ + static inline GLint -unzoom_x(GLfloat zoomX, GLint imageX, GLint zx) +positive_unzoom_x(GLfloat xfactor, GLint xr, GLint xz) { /* - zx = imageX + (x - imageX) * zoomX; - zx - imageX = (x - imageX) * zoomX; - (zx - imageX) / zoomX = x - imageX; - */ - GLint x; - if (zoomX < 0.0) - zx++; - x = imageX + (GLint) ((zx - imageX) / zoomX); - return x; + * OpenGL definition, when xfactor > 0: + * + * LEFT EDGE RIGHT EDGE + * xr + n * xfactor <= xz < xr + (n + 1) * xfactor + * + * Subtract raster position: + * + * n * xfactor <= xz - xr < (n + 1) * xfactor + * + * Divide by xfactor > 0: + * + * n <= (xz - xr) / xfactor < n + 1 + * + * or + * + * n = floor((xz - xr) / xfactor) [1] + */ + + GLint n; + GLint xarg; + + /* Implement [1] */ + + xarg = (xz - xr) / xfactor + EPSFLOOR; + +#if 1 + n = (GLint) floorf(xarg); +#else + n = (GLint) (xarg); + if (xarg < 0.0 && (n != xarg)) + n--; +#endif + + return (xr + n); } +static inline GLint +negative_unzoom_x(GLfloat xfactor, GLint xr, GLint xz) + { + /* + * OpenGL definition, when xfactor < 0: + * + * LEFT EDGE RIGHT EDGE + * xr + (n + 1) * xfactor <= xz < xr + n * xfactor + * + * Subtract raster position: + * + * (n + 1) * xfactor <= xz - xr < n * xfactor + * + * For xfactor < 0: + * + * (n + 1) >= (xz - xr) / xfactor > n + * + * or + * + * (n + 1) = ceil((xz - xr) / xfactor) + * + * Subtract 1: + * + * n = ceil((xz - xr) / xfactor) - 1; [2] + */ + + GLint n; + GLfloat xarg; + + /* Implement [2] */ + + xarg = (xz - xr) / xfactor - EPSCEIL; + +#if 1 + n = (GLint) (ceilf(xarg) - 1.0); +#else + n = (GLint) (xarg); + if (xarg <= 0.0 || (n == xarg)) + n--; +#endif + + return (xr + n); +} + + +static inline GLint +unzoom_x(GLfloat zoomX, GLint imageX, GLint zx) +{ + if (zoomX >= 0.0) + return positive_unzoom_x(zoomX, imageX, zx); + else + return negative_unzoom_x(zoomX, imageX, zx); +} /** @@ -135,8 +246,9 @@ zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span, SWspan zoomed; GLint x0, x1, y0, y1; GLint zoomedWidth; + GLint spanX = span->x; - if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end, + if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, span->y, span->end, &x0, &x1, &y0, &y1)) { return; /* totally clipped */ } @@ -210,85 +322,51 @@ zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span, 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); + SPAN_LOOP_X( 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); + SPAN_LOOP_X( 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 < (GLint) span->end); + SPAN_LOOP_X( COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][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]; + SPAN_LOOP_X( + COPY_3V(zoomed.array->rgba8[i], rgb[j]); 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]; + SPAN_LOOP_X( + COPY_3V(zoomed.array->rgba16[i], rgb[j]); 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 < (GLint) span->end); - zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0]; - zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1]; - zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2]; + SPAN_LOOP_X( + COPY_3V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgb[j]); zoomed.array->attribs[VARYING_SLOT_COL0][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); + SPAN_LOOP_X( zoomed.array->z[i] = zValues[j]; - } + ); /* Now, fall into the RGB path below */ format = GL_RGBA; } @@ -364,7 +442,7 @@ _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY { GLubyte *zoomedVals; GLint x0, x1, y0, y1, y; - GLint i, zoomedWidth; + GLint zoomedWidth; if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, &x0, &x1, &y0, &y1)) { @@ -380,12 +458,9 @@ _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY return; /* 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); + SPAN_LOOP_X( zoomedVals[i] = stencil[j]; - } + ); /* write the zoomed spans */ for (y = y0; y < y1; y++) { @@ -409,7 +484,7 @@ _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY, ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLuint *zoomedVals; GLint x0, x1, y0, y1, y; - GLint i, zoomedWidth; + GLint zoomedWidth; if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, &x0, &x1, &y0, &y1)) { @@ -425,12 +500,9 @@ _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY, return; /* 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); + SPAN_LOOP_X( zoomedVals[i] = zVals[j]; - } + ); /* write the zoomed spans */ for (y = y0; y < y1; y++) { -- 1.7.4.4