/* * Mesa 3-D graphics library * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "main/glheader.h" #include "main/context.h" #include "main/formats.h" #include "main/format_unpack.h" #include "main/format_pack.h" #include "main/macros.h" #include "util/imports.h" #include "s_context.h" #include "s_depth.h" #include "s_span.h" #define Z_TEST(COMPARE) \ do { \ GLuint i; \ for (i = 0; i < n; i++) { \ if (mask[i]) { \ if (COMPARE) { \ /* pass */ \ if (write) { \ zbuffer[i] = zfrag[i]; \ } \ passed++; \ } \ else { \ /* fail */ \ mask[i] = 0; \ } \ } \ } \ } while (0) /** * Do depth test for an array of 16-bit Z values. * @param zbuffer array of Z buffer values (16-bit) * @param zfrag array of fragment Z values (use 16-bit in 32-bit uint) * @param mask which fragments are alive, killed afterward * @return number of fragments which pass the test. */ static GLuint depth_test_span16( struct gl_context *ctx, GLuint n, GLushort zbuffer[], const GLuint zfrag[], GLubyte mask[] ) { const GLboolean write = ctx->Depth.Mask; GLuint passed = 0; /* switch cases ordered from most frequent to less frequent */ switch (ctx->Depth.Func) { case GL_LESS: Z_TEST(zfrag[i] < zbuffer[i]); break; case GL_LEQUAL: Z_TEST(zfrag[i] <= zbuffer[i]); break; case GL_GEQUAL: Z_TEST(zfrag[i] >= zbuffer[i]); break; case GL_GREATER: Z_TEST(zfrag[i] > zbuffer[i]); break; case GL_NOTEQUAL: Z_TEST(zfrag[i] != zbuffer[i]); break; case GL_EQUAL: Z_TEST(zfrag[i] == zbuffer[i]); break; case GL_ALWAYS: Z_TEST(1); break; case GL_NEVER: memset(mask, 0, n * sizeof(GLubyte)); break; default: _mesa_problem(ctx, "Bad depth func in depth_test_span16"); } return passed; } /** * Do depth test for an array of 32-bit Z values. * @param zbuffer array of Z buffer values (32-bit) * @param zfrag array of fragment Z values (use 32-bits in 32-bit uint) * @param mask which fragments are alive, killed afterward * @return number of fragments which pass the test. */ static GLuint depth_test_span32( struct gl_context *ctx, GLuint n, GLuint zbuffer[], const GLuint zfrag[], GLubyte mask[]) { const GLboolean write = ctx->Depth.Mask; GLuint passed = 0; /* switch cases ordered from most frequent to less frequent */ switch (ctx->Depth.Func) { case GL_LESS: Z_TEST(zfrag[i] < zbuffer[i]); break; case GL_LEQUAL: Z_TEST(zfrag[i] <= zbuffer[i]); break; case GL_GEQUAL: Z_TEST(zfrag[i] >= zbuffer[i]); break; case GL_GREATER: Z_TEST(zfrag[i] > zbuffer[i]); break; case GL_NOTEQUAL: Z_TEST(zfrag[i] != zbuffer[i]); break; case GL_EQUAL: Z_TEST(zfrag[i] == zbuffer[i]); break; case GL_ALWAYS: Z_TEST(1); break; case GL_NEVER: memset(mask, 0, n * sizeof(GLubyte)); break; default: _mesa_problem(ctx, "Bad depth func in depth_test_span32"); } return passed; } /** * Clamp fragment Z values to the depth near/far range (glDepthRange()). * This is used when GL_ARB_depth_clamp/GL_DEPTH_CLAMP is turned on. * In that case, vertexes are not clipped against the near/far planes * so rasterization will produce fragment Z values outside the usual * [0,1] range. */ void _swrast_depth_clamp_span( struct gl_context *ctx, SWspan *span ) { struct gl_framebuffer *fb = ctx->DrawBuffer; const GLuint count = span->end; GLint *zValues = (GLint *) span->array->z; /* sign change */ GLint min, max; GLfloat min_f, max_f; GLuint i; if (ctx->ViewportArray[0].Near < ctx->ViewportArray[0].Far) { min_f = ctx->ViewportArray[0].Near; max_f = ctx->ViewportArray[0].Far; } else { min_f = ctx->ViewportArray[0].Far; max_f = ctx->ViewportArray[0].Near; } /* Convert floating point values in [0,1] to device Z coordinates in * [0, DepthMax]. * ex: If the Z buffer has 24 bits, DepthMax = 0xffffff. * * XXX this all falls apart if we have 31 or more bits of Z because * the triangle rasterization code produces unsigned Z values. Negative * vertex Z values come out as large fragment Z uints. */ min = (GLint) (min_f * fb->_DepthMaxF); max = (GLint) (max_f * fb->_DepthMaxF); if (max < 0) max = 0x7fffffff; /* catch over flow for 30-bit z */ /* Note that we do the comparisons here using signed integers. */ for (i = 0; i < count; i++) { if (zValues[i] < min) zValues[i] = min; if (zValues[i] > max) zValues[i] = max; } } /** * 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 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 { mesa_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 { /* 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) { GLuint i; /* Convert depth buffer values from 32 to 16 bits */ for (i = 0; i < count; i++) { zBufferTemp[i] >>= 16; } } else { assert(zBits == 32); } zBufferVals = zBufferTemp; } /* do the depth test either with 16 or 32-bit values */ if (ztest16) passed = depth_test_span16(ctx, count, zBufferVals, fragZ, mask); else passed = depth_test_span32(ctx, count, zBufferVals, fragZ, mask); if (zBufferTemp) { /* need to write temp Z values back into the buffer */ /* Convert depth buffer values back to 32-bit values. The least * significant bits don't matter since they'll get dropped when * they're packed back into the depth buffer. */ if (zBits == 24) { GLuint i; for (i = 0; i < count; i++) { zBufferTemp[i] = (zBufferTemp[i] << 8); } } else if (zBits == 16) { GLuint i; for (i = 0; i < count; i++) { zBufferTemp[i] = zBufferTemp[i] << 16; } } if (span->arrayMask & SPAN_XY) { /* random locations */ put_z32_values(ctx, rb, count, span->array->x, span->array->y, zBufferTemp, mask); } else { /* horizontal row */ mesa_pack_uint_z_func packZ = _mesa_get_pack_uint_z_func(rb->Format); GLubyte *dst = zStart; GLuint i; for (i = 0; i < count; i++) { if (mask[i]) { packZ(&zBufferTemp[i], dst); } dst += bpp; } } free(zBufferTemp); } if (passed < count) { span->writeAll = GL_FALSE; } return passed; } /** * GL_EXT_depth_bounds_test extension. * Discard fragments depending on whether the corresponding Z-buffer * values are outside the depth bounds test range. * Note: we test the Z buffer values, not the fragment Z values! * \return GL_TRUE if any fragments pass, GL_FALSE if no fragments pass */ GLboolean _swrast_depth_bounds_test( struct gl_context *ctx, SWspan *span ) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; GLubyte *zStart; GLuint zMin = (GLuint)((double)ctx->Depth.BoundsMin * 0xffffffff); GLuint zMax = (GLuint)((double)ctx->Depth.BoundsMax * 0xffffffff); GLubyte *mask = span->array->mask; const GLuint count = span->end; GLuint i; GLboolean anyPass = GL_FALSE; GLuint *zBufferTemp; const GLuint *zBufferVals; zBufferTemp = malloc(count * sizeof(GLuint)); if (!zBufferTemp) { /* don't generate a stream of OUT_OF_MEMORY errors here */ return 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_UNORM32 && !(span->arrayMask & SPAN_XY)) { /* directly access 32-bit values in the depth buffer */ zBufferVals = (const GLuint *) zStart; } else { /* Round the bounds to the precision of the zbuffer. */ if (rb->Format == MESA_FORMAT_Z_UNORM16) { zMin = (zMin & 0xffff0000) | (zMin >> 16); zMax = (zMax & 0xffff0000) | (zMax >> 16); } else { /* 24 bits */ zMin = (zMin & 0xffffff00) | (zMin >> 24); zMax = (zMax & 0xffffff00) | (zMax >> 24); } /* unpack Z values into a temporary array */ 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); } zBufferVals = zBufferTemp; } /* Now do the tests */ for (i = 0; i < count; i++) { if (mask[i]) { if (zBufferVals[i] < zMin || zBufferVals[i] > zMax) mask[i] = GL_FALSE; else anyPass = GL_TRUE; } } free(zBufferTemp); return anyPass; } /**********************************************************************/ /***** Read Depth Buffer *****/ /**********************************************************************/ /** * Read a span of depth values from the given depth renderbuffer, returning * the values as GLfloats. * This function does clipping to prevent reading outside the depth buffer's * bounds. */ void _swrast_read_depth_span_float(struct gl_context *ctx, struct gl_renderbuffer *rb, GLint n, GLint x, GLint y, GLfloat depth[]) { if (!rb) { /* really only doing this to prevent FP exceptions later */ memset(depth, 0, n * sizeof(GLfloat)); return; } if (y < 0 || y >= (GLint) rb->Height || x + n <= 0 || x >= (GLint) rb->Width) { /* span is completely outside framebuffer */ memset(depth, 0, n * sizeof(GLfloat)); return; } if (x < 0) { GLint dx = -x; GLint i; for (i = 0; i < dx; i++) depth[i] = 0.0; x = 0; n -= dx; depth += dx; } if (x + n > (GLint) rb->Width) { GLint dx = x + n - (GLint) rb->Width; GLint i; for (i = 0; i < dx; i++) depth[n - i - 1] = 0.0; n -= dx; } if (n <= 0) { return; } _mesa_unpack_float_z_row(rb->Format, n, _swrast_pixel_address(rb, x, y), depth); } /** * Clear the given z/depth renderbuffer. If the buffer is a combined * depth+stencil buffer, only the Z bits will be touched. */ void _swrast_clear_depth_buffer(struct gl_context *ctx) { struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLint x, y, width, height; GLubyte *map; GLint rowStride, i, j; GLbitfield mapMode; if (!rb || !ctx->Depth.Mask) { /* no depth buffer, or writing to it is disabled */ return; } /* compute region to clear */ x = ctx->DrawBuffer->_Xmin; y = ctx->DrawBuffer->_Ymin; width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; mapMode = GL_MAP_WRITE_BIT; if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT || rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT || rb->Format == MESA_FORMAT_S8_UINT_Z24_UNORM || rb->Format == MESA_FORMAT_X8_UINT_Z24_UNORM) { mapMode |= GL_MAP_READ_BIT; } ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, mapMode, &map, &rowStride, ctx->DrawBuffer->FlipY); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth)"); return; } switch (rb->Format) { case MESA_FORMAT_Z_UNORM16: { GLfloat clear = (GLfloat) ctx->Depth.Clear; GLushort clearVal = 0; _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal); if (clearVal == 0xffff && width * 2 == rowStride) { /* common case */ memset(map, 0xff, width * height * 2); } else { for (i = 0; i < height; i++) { GLushort *row = (GLushort *) map; for (j = 0; j < width; j++) { row[j] = clearVal; } map += rowStride; } } } break; case MESA_FORMAT_Z_UNORM32: case MESA_FORMAT_Z_FLOAT32: { GLfloat clear = (GLfloat) ctx->Depth.Clear; GLuint clearVal = 0; _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal); for (i = 0; i < height; i++) { GLuint *row = (GLuint *) map; for (j = 0; j < width; j++) { row[j] = clearVal; } map += rowStride; } } break; case MESA_FORMAT_Z24_UNORM_S8_UINT: case MESA_FORMAT_Z24_UNORM_X8_UINT: case MESA_FORMAT_S8_UINT_Z24_UNORM: case MESA_FORMAT_X8_UINT_Z24_UNORM: { GLfloat clear = (GLfloat) ctx->Depth.Clear; GLuint clearVal = 0; GLuint mask; if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT || rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT) mask = 0xff000000; else mask = 0xff; _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal); for (i = 0; i < height; i++) { GLuint *row = (GLuint *) map; for (j = 0; j < width; j++) { row[j] = (row[j] & mask) | clearVal; } map += rowStride; } } break; case MESA_FORMAT_Z32_FLOAT_S8X24_UINT: /* XXX untested */ { GLfloat clearVal = (GLfloat) ctx->Depth.Clear; for (i = 0; i < height; i++) { GLfloat *row = (GLfloat *) map; for (j = 0; j < width; j++) { row[j * 2] = clearVal; } map += rowStride; } } break; default: _mesa_problem(ctx, "Unexpected depth buffer format %s" " in _swrast_clear_depth_buffer()", _mesa_get_format_name(rb->Format)); } ctx->Driver.UnmapRenderbuffer(ctx, rb); } /** * Clear both depth and stencil values in a combined depth+stencil buffer. */ void _swrast_clear_depth_stencil_buffer(struct gl_context *ctx) { const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; const GLuint writeMask = ctx->Stencil.WriteMask[0]; const GLuint stencilMax = (1 << stencilBits) - 1; struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLint x, y, width, height; GLbitfield mapMode; GLubyte *map; GLint rowStride, i, j; /* check that we really have a combined depth+stencil buffer */ assert(rb == ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer); /* compute region to clear */ x = ctx->DrawBuffer->_Xmin; y = ctx->DrawBuffer->_Ymin; width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; mapMode = GL_MAP_WRITE_BIT; if ((writeMask & stencilMax) != stencilMax) { /* need to mask stencil values */ mapMode |= GL_MAP_READ_BIT; } ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, mapMode, &map, &rowStride, ctx->DrawBuffer->FlipY); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth+stencil)"); return; } switch (rb->Format) { case MESA_FORMAT_Z24_UNORM_S8_UINT: case MESA_FORMAT_S8_UINT_Z24_UNORM: { GLfloat zClear = (GLfloat) ctx->Depth.Clear; GLuint clear = 0, mask; _mesa_pack_float_z_row(rb->Format, 1, &zClear, &clear); if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT) { mask = ((~writeMask) & 0xff) << 24; clear |= (ctx->Stencil.Clear & writeMask & 0xff) << 24; } else { mask = ((~writeMask) & 0xff); clear |= (ctx->Stencil.Clear & writeMask & 0xff); } for (i = 0; i < height; i++) { GLuint *row = (GLuint *) map; if (mask != 0x0) { for (j = 0; j < width; j++) { row[j] = (row[j] & mask) | clear; } } else { for (j = 0; j < width; j++) { row[j] = clear; } } map += rowStride; } } break; case MESA_FORMAT_Z32_FLOAT_S8X24_UINT: /* XXX untested */ { const GLfloat zClear = (GLfloat) ctx->Depth.Clear; const GLuint sClear = ctx->Stencil.Clear & writeMask; const GLuint sMask = (~writeMask) & 0xff; for (i = 0; i < height; i++) { GLfloat *zRow = (GLfloat *) map; GLuint *sRow = (GLuint *) map; for (j = 0; j < width; j++) { zRow[j * 2 + 0] = zClear; } if (sMask != 0) { for (j = 0; j < width; j++) { sRow[j * 2 + 1] = (sRow[j * 2 + 1] & sMask) | sClear; } } else { for (j = 0; j < width; j++) { sRow[j * 2 + 1] = sClear; } } map += rowStride; } } break; default: _mesa_problem(ctx, "Unexpected depth buffer format %s" " in _swrast_clear_depth_buffer()", _mesa_get_format_name(rb->Format)); } ctx->Driver.UnmapRenderbuffer(ctx, rb); }