/** * Put an array of 32-bit z values into the depth buffer. * Note: the z values are always in the range [0, 2^32-1]. */ static void put_z32_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], const GLuint zvalues[], const GLubyte mask[]) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); const GLint w = rb->Width, h = rb->Height; GLubyte *map = _swrast_pixel_address(rb, 0, 0); GLuint i; if (rb->Format == MESA_FORMAT_Z_UNORM32) { const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (mask[i] && x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { GLuint *dst = (GLuint *) (map + y[i] * rowStride + x[i] * 4); *dst = zvalues[i]; } } } else { gl_pack_uint_z_func packZ = _mesa_get_pack_uint_z_func(rb->Format); const GLint bpp = _mesa_get_format_bytes(rb->Format); const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (mask[i] && x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { void *dst = map + y[i] * rowStride + x[i] * bpp; packZ(zvalues + i, dst); } } } }
/** * Apply depth (Z) buffer testing to the span. * \return approx number of pixels that passed (only zero is reliable) */ GLuint _swrast_depth_test_span(struct gl_context *ctx, SWspan *span) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; const GLint bpp = _mesa_get_format_bytes(rb->Format); void *zStart; const GLuint count = span->end; const GLuint *fragZ = span->array->z; GLubyte *mask = span->array->mask; void *zBufferVals; GLuint *zBufferTemp = NULL; GLuint passed; GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS); GLboolean ztest16 = GL_FALSE; if (span->arrayMask & SPAN_XY) zStart = NULL; else zStart = _swrast_pixel_address(rb, span->x, span->y); if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 16-bit Z values */ zBufferVals = zStart; ztest16 = GL_TRUE; } else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 32-bit Z values */ zBufferVals = zStart; } else { if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) { _mesa_problem(ctx, "Incorrectly writing swrast's integer depth " "values to %s depth buffer", _mesa_get_format_name(rb->Format)); } /* copy Z buffer values into temp buffer (32-bit Z values) */ zBufferTemp = malloc(count * sizeof(GLuint)); if (!zBufferTemp) return 0; if (span->arrayMask & SPAN_XY) { get_z32_values(ctx, rb, count, span->array->x, span->array->y, zBufferTemp); } else { _mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp); } if (zBits == 24) { GLuint i; /* Convert depth buffer values from 32 to 24 bits to match the * fragment Z values generated by rasterization. */ for (i = 0; i < count; i++) { zBufferTemp[i] >>= 8; } } else if (zBits == 16) {
/** * Zoom/write 32-bit Z values. * No per-fragment operations are applied. */ void _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY, GLint width, GLint spanX, GLint spanY, const GLuint *zVals) { struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLuint 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] = zVals[j]; } /* write the zoomed spans */ for (y = y0; y < y1; y++) { GLubyte *dst = _swrast_pixel_address(rb, x0, y); _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst); } }
/** * Get array of 32-bit z values from the depth buffer. With clipping. * Note: the returned values are always in the range [0, 2^32-1]. */ static void get_z32_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], GLuint zbuffer[]) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); const GLint w = rb->Width, h = rb->Height; const GLubyte *map = _swrast_pixel_address(rb, 0, 0); GLuint i; if (rb->Format == MESA_FORMAT_Z_UNORM32) { const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { zbuffer[i] = *((GLuint *) (map + y[i] * rowStride + x[i] * 4)); } } } else { const GLint bpp = _mesa_get_format_bytes(rb->Format); const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { const GLubyte *src = map + y[i] * rowStride+ x[i] * bpp; _mesa_unpack_uint_z_row(rb->Format, 1, src, &zbuffer[i]); } } } }
/** Put colors at x/y locations into a renderbuffer */ static void put_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum datatype, GLuint count, const GLint x[], const GLint y[], const void *values, const GLubyte *mask) { gl_pack_ubyte_rgba_func pack_ubyte; gl_pack_float_rgba_func pack_float; GLuint i; if (datatype == GL_UNSIGNED_BYTE) pack_ubyte = _mesa_get_pack_ubyte_rgba_function(rb->Format); else pack_float = _mesa_get_pack_float_rgba_function(rb->Format); for (i = 0; i < count; i++) { if (mask[i]) { GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]); if (datatype == GL_UNSIGNED_BYTE) { pack_ubyte((const GLubyte *) values + 4 * i, dst); } else { assert(datatype == GL_FLOAT); pack_float((const GLfloat *) values + 4 * i, dst); } } } }
/** * Get colors at x/y positions with clipping. * \param type type of values to return */ static void get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], void *values, GLenum type) { GLuint i; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) { /* inside */ const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]); if (type == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src, (GLubyte (*)[4]) values + i); } else if (type == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, 1, src, (GLfloat (*)[4]) values + i); } else { _mesa_problem(ctx, "unexpected type in get_values()"); } } } }
/** * Return a span of stencil values from the stencil buffer. * Used for glRead/CopyPixels * Input: n - how many pixels * x,y - location of first pixel * Output: stencil - the array of stencil values */ void _swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb, GLint n, GLint x, GLint y, GLubyte stencil[]) { GLubyte *src; if (y < 0 || y >= (GLint) rb->Height || x + n <= 0 || x >= (GLint) rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } if (x < 0) { GLint dx = -x; x = 0; n -= dx; stencil += dx; } if (x + n > (GLint) rb->Width) { GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } src = _swrast_pixel_address(rb, x, y); _mesa_unpack_ubyte_stencil_row(rb->Format, n, src, stencil); }
/** Put row of colors into renderbuffer */ void _swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum datatype, GLuint count, GLint x, GLint y, const void *values, const GLubyte *mask) { GLubyte *dst = _swrast_pixel_address(rb, x, y); if (!mask) { if (datatype == GL_UNSIGNED_BYTE) { _mesa_pack_ubyte_rgba_row(rb->Format, count, (const GLubyte (*)[4]) values, dst); } else { assert(datatype == GL_FLOAT); _mesa_pack_float_rgba_row(rb->Format, count, (const GLfloat (*)[4]) values, dst); } } else { const GLuint bpp = _mesa_get_format_bytes(rb->Format); GLuint i, runLen, runStart; /* We can't pass a 'mask' array to the _mesa_pack_rgba_row() functions * so look for runs where mask=1... */ runLen = runStart = 0; for (i = 0; i < count; i++) { if (mask[i]) { if (runLen == 0) runStart = i; runLen++; } if (!mask[i] || i == count - 1) { /* might be the end of a run of pixels */ if (runLen > 0) { if (datatype == GL_UNSIGNED_BYTE) { _mesa_pack_ubyte_rgba_row(rb->Format, runLen, (const GLubyte (*)[4]) values + runStart, dst + runStart * bpp); } else { assert(datatype == GL_FLOAT); _mesa_pack_float_rgba_row(rb->Format, runLen, (const GLfloat (*)[4]) values + runStart, dst + runStart * bpp); } runLen = 0; } } } } }
/** * Write a span of stencil values to the stencil buffer. This function * applies the stencil write mask when needed. * Used for glDraw/CopyPixels * Input: n - how many pixels * x, y - location of first pixel * stencil - the array of stencil values */ void _swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y, const GLubyte stencil[] ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; const GLuint stencilMask = ctx->Stencil.WriteMask[0]; GLubyte *stencilBuf; if (y < 0 || y >= (GLint) rb->Height || x + n <= 0 || x >= (GLint) rb->Width) { /* span is completely outside framebuffer */ return; /* undefined values OK */ } if (x < 0) { GLint dx = -x; x = 0; n -= dx; stencil += dx; } if (x + n > (GLint) rb->Width) { GLint dx = x + n - rb->Width; n -= dx; } if (n <= 0) { return; } stencilBuf = _swrast_pixel_address(rb, x, y); if ((stencilMask & stencilMax) != stencilMax) { /* need to apply writemask */ GLubyte *destVals = swrast->stencil_temp.buf1; GLubyte *newVals = swrast->stencil_temp.buf2; GLint i; _mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals); for (i = 0; i < n; i++) { newVals[i] = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); } _mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf); } else { _mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf); } }
/** * Put 8-bit stencil values at random locations into the stencil buffer. */ static void put_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], const GLubyte stencil[]) { const GLint w = rb->Width, h = rb->Height; gl_pack_ubyte_stencil_func pack_stencil = _mesa_get_pack_ubyte_stencil_func(rb->Format); GLuint i; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]); pack_stencil(&stencil[i], dst); } } }
/** * Get row of colors with clipping. * \param type type of values to return */ static void get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, GLint x, GLint y, GLvoid *values, GLenum type) { GLint skip = 0; GLubyte *src; if (y < 0 || y >= (GLint) rb->Height) return; /* above or below */ if (x + (GLint) count <= 0 || x >= (GLint) rb->Width) return; /* entirely left or right */ if (x + count > rb->Width) { /* right clip */ GLint clip = x + count - rb->Width; count -= clip; } if (x < 0) { /* left clip */ skip = -x; x = 0; count -= skip; } src = _swrast_pixel_address(rb, x, y); if (type == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, count, src, (GLubyte (*)[4]) values + skip); } else if (type == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, count, src, (GLfloat (*)[4]) values + skip); } else { _mesa_problem(ctx, "unexpected type in get_row()"); } }
/** * Read float RGBA pixels from a renderbuffer. Clipping will be done to * prevent reading ouside the buffer's boundaries. * \param rgba the returned colors */ void _swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, GLvoid *rgba) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); GLenum dstType = GL_FLOAT; const GLint bufWidth = (GLint) rb->Width; const GLint bufHeight = (GLint) rb->Height; if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { /* completely above, below, or right */ /* XXX maybe leave rgba values undefined? */ memset(rgba, 0, 4 * n * sizeof(GLchan)); } else { GLint skip, length; GLubyte *src; if (x < 0) { /* left edge clipping */ skip = -x; length = (GLint) n - skip; if (length < 0) { /* completely left of window */ return; } if (length > bufWidth) { length = bufWidth; } } else if ((GLint) (x + n) > bufWidth) { /* right edge clipping */ skip = 0; length = bufWidth - x; if (length < 0) { /* completely to right of window */ return; } } else { /* no clipping */ skip = 0; length = (GLint) n; } ASSERT(rb); ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RG || rb->_BaseFormat == GL_RED || rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY || rb->_BaseFormat == GL_LUMINANCE_ALPHA || rb->_BaseFormat == GL_ALPHA); assert(srb->Map); src = _swrast_pixel_address(rb, x + skip, y); if (dstType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, length, src, (GLubyte (*)[4]) rgba + skip); } else if (dstType == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, length, src, (GLfloat (*)[4]) rgba + skip); } else { _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()"); } } }
/** * /return GL_TRUE = one or more fragments passed, * GL_FALSE = all fragments failed. */ GLboolean _swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; const GLint stencilOffset = get_stencil_offset(rb->Format); const GLint stencilStride = _mesa_get_format_bytes(rb->Format); const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace; const GLuint count = span->end; GLubyte *mask = span->array->mask; GLubyte stencilTemp[MAX_WIDTH]; GLubyte *stencilBuf; if (span->arrayMask & SPAN_XY) { /* read stencil values from random locations */ get_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilTemp); stencilBuf = stencilTemp; } else { /* Processing a horizontal run of pixels. Since stencil is always * 8 bits for all MESA_FORMATs, we just need to use the right offset * and stride to access them. */ stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset; } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; if (span->arrayMask & SPAN_XY) { /* need to write the updated stencil values back to the buffer */ put_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilTemp); } return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE || ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, stencilBuf, mask, stencilStride); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; /* save the current mask bits */ memcpy(origMask, mask, count * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); compute_pass_fail_masks(count, origMask, mask, passMask, failMask); /* apply the pass and fail operations */ if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, count, stencilBuf, failMask, stencilStride); } if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, stencilBuf, passMask, stencilStride); } } /* Write updated stencil values back into hardware stencil buffer */ if (span->arrayMask & SPAN_XY) { put_s8_values(ctx, rb, count, span->array->x, span->array->y, stencilBuf); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */ }