From fd104a84591ae854c5d6adc81e2dc31ef6ab9e8a Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Sat, 24 Dec 2011 08:54:25 -0700 Subject: [PATCH] swrast: do depth/stencil clearing with Map/UnmapRenderbuffer() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Another step toward getting rid of the renderbuffer PutRow/etc functions. v2: fix assorted depth/stencil clear bugs found by Eric Reviewed-by: José Fonseca --- src/mesa/swrast/s_clear.c | 49 +++++--- src/mesa/swrast/s_depth.c | 235 ++++++++++++++++++++++++++++++------ src/mesa/swrast/s_depth.h | 5 +- src/mesa/swrast/s_stencil.c | 154 +++++++++++------------ src/mesa/swrast/s_stencil.h | 2 +- 5 files changed, 305 insertions(+), 140 deletions(-) diff --git a/src/mesa/swrast/s_clear.c b/src/mesa/swrast/s_clear.c index 851f6d16567..35663700535 100644 --- a/src/mesa/swrast/s_clear.c +++ b/src/mesa/swrast/s_clear.c @@ -195,6 +195,8 @@ clear_color_buffers(struct gl_context *ctx) void _swrast_Clear(struct gl_context *ctx, GLbitfield buffers) { + const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL; + #ifdef DEBUG_FOO { const GLbitfield legalBits = @@ -216,24 +218,39 @@ _swrast_Clear(struct gl_context *ctx, GLbitfield buffers) if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived(ctx); - swrast_render_start(ctx); + if ((buffers & BUFFER_BITS_COLOR) + && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) { + /* XXX remove the swrast_render_start/finish() calls after + * clear_color_buffers() is converted to use Map/UnmapRenderbuffer() + * The other clearing functions don't need these calls. + */ + swrast_render_start(ctx); + clear_color_buffers(ctx); + swrast_render_finish(ctx); + } - /* do software clearing here */ - if (buffers) { - if ((buffers & BUFFER_BITS_COLOR) - && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) { - clear_color_buffers(ctx); - } - if (buffers & BUFFER_BIT_DEPTH) { - _swrast_clear_depth_buffer(ctx, ctx->DrawBuffer->_DepthBuffer); - } - if (buffers & BUFFER_BIT_ACCUM) { - _mesa_clear_accum_buffer(ctx); + if (buffers & BUFFER_BIT_ACCUM) { + _mesa_clear_accum_buffer(ctx); + } + + if (buffers & BUFFER_DS) { + struct gl_renderbuffer *depthRb = + ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *stencilRb = + ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + + if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) { + /* clear depth and stencil together */ + _swrast_clear_depth_stencil_buffer(ctx); } - if (buffers & BUFFER_BIT_STENCIL) { - _swrast_clear_stencil_buffer(ctx, ctx->DrawBuffer->_StencilBuffer); + else { + /* clear depth, stencil separately */ + if (buffers & BUFFER_BIT_DEPTH) { + _swrast_clear_depth_buffer(ctx); + } + if (buffers & BUFFER_BIT_STENCIL) { + _swrast_clear_stencil_buffer(ctx); + } } } - - swrast_render_finish(ctx); } diff --git a/src/mesa/swrast/s_depth.c b/src/mesa/swrast/s_depth.c index 8d3ad105bce..09c0be68f07 100644 --- a/src/mesa/swrast/s_depth.c +++ b/src/mesa/swrast/s_depth.c @@ -26,6 +26,7 @@ #include "main/glheader.h" #include "main/context.h" #include "main/formats.h" +#include "main/format_pack.h" #include "main/macros.h" #include "main/imports.h" @@ -1312,14 +1313,21 @@ _swrast_read_depth_span_float( struct gl_context *ctx, struct gl_renderbuffer *r } } + /** - * Clear the given z/depth renderbuffer. + * 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 ) +_swrast_clear_depth_buffer(struct gl_context *ctx) { + struct gl_renderbuffer *rb = + ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLuint clearValue; 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 */ @@ -1334,67 +1342,218 @@ _swrast_clear_depth_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb ) clearValue = (GLuint) (ctx->Depth.Clear * ctx->DrawBuffer->_DepthMaxF); } - assert(rb->_BaseFormat == GL_DEPTH_COMPONENT); - /* 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; - if (rb->GetPointer(ctx, rb, 0, 0)) { - /* Direct buffer access is possible. Either this is just malloc'd - * memory, or perhaps the driver mmap'd the zbuffer memory. - */ - if (rb->DataType == GL_UNSIGNED_SHORT) { - if ((clearValue & 0xff) == ((clearValue >> 8) & 0xff) && - ((GLushort *) rb->GetPointer(ctx, rb, 0, 0) + width == - (GLushort *) rb->GetPointer(ctx, rb, 0, 1))) { - /* optimized case */ - GLushort *dst = (GLushort *) rb->GetPointer(ctx, rb, x, y); - GLuint len = width * height * sizeof(GLushort); - memset(dst, (clearValue & 0xff), len); + mapMode = GL_MAP_WRITE_BIT; + if (rb->Format == MESA_FORMAT_S8_Z24 || + rb->Format == MESA_FORMAT_X8_Z24 || + rb->Format == MESA_FORMAT_Z24_S8 || + rb->Format == MESA_FORMAT_Z24_X8) { + mapMode |= GL_MAP_READ_BIT; + } + + ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, + mapMode, &map, &rowStride); + if (!map) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth)"); + return; + } + + switch (rb->Format) { + case MESA_FORMAT_Z16: + { + 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 { - /* general case */ - GLint i, j; for (i = 0; i < height; i++) { - GLushort *dst = (GLushort *) rb->GetPointer(ctx, rb, x, y + i); + GLushort *row = (GLushort *) map; for (j = 0; j < width; j++) { - dst[j] = clearValue; + row[j] = clearVal; } + map += rowStride; } } } - else { - GLint i, j; - ASSERT(rb->DataType == GL_UNSIGNED_INT); + break; + case MESA_FORMAT_Z32: + case MESA_FORMAT_Z32_FLOAT: + { + 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 *dst = (GLuint *) rb->GetPointer(ctx, rb, x, y + i); + GLuint *row = (GLuint *) map; for (j = 0; j < width; j++) { - dst[j] = clearValue; + row[j] = clearVal; } + map += rowStride; } } - } - else { - /* Direct access not possible. Use PutRow to write new values. */ - if (rb->DataType == GL_UNSIGNED_SHORT) { - GLushort clearVal16 = (GLushort) (clearValue & 0xffff); - GLint i; + break; + case MESA_FORMAT_S8_Z24: + case MESA_FORMAT_X8_Z24: + case MESA_FORMAT_Z24_S8: + case MESA_FORMAT_Z24_X8: + { + GLfloat clear = (GLfloat) ctx->Depth.Clear; + GLuint clearVal = 0; + GLuint mask; + + if (rb->Format == MESA_FORMAT_S8_Z24 || + rb->Format == MESA_FORMAT_X8_Z24) + mask = 0xff000000; + else + mask = 0xff; + + _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal); for (i = 0; i < height; i++) { - rb->PutMonoRow(ctx, rb, width, x, y + i, &clearVal16, NULL); + GLuint *row = (GLuint *) map; + for (j = 0; j < width; j++) { + row[j] = (row[j] & mask) | clearVal; + } + map += rowStride; } + } - else if (rb->DataType == GL_UNSIGNED_INT) { - GLint i; - ASSERT(sizeof(clearValue) == sizeof(GLuint)); + break; + case MESA_FORMAT_Z32_FLOAT_X24S8: + /* XXX untested */ + { + GLfloat clearVal = (GLfloat) ctx->Depth.Clear; for (i = 0; i < height; i++) { - rb->PutMonoRow(ctx, rb, width, x, y + i, &clearValue, NULL); + GLfloat *row = (GLfloat *) map; + for (j = 0; j < width; j++) { + row[j * 2] = clearVal; + } + map += rowStride; } } - else { - _mesa_problem(ctx, "bad depth renderbuffer DataType"); + 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); + if (!map) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth+stencil)"); + return; + } + + switch (rb->Format) { + case MESA_FORMAT_S8_Z24: + case MESA_FORMAT_Z24_S8: + { + 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_S8_Z24) { + 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_X24S8: + /* 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); + } diff --git a/src/mesa/swrast/s_depth.h b/src/mesa/swrast/s_depth.h index 2caea82e081..25a7a0bbf83 100644 --- a/src/mesa/swrast/s_depth.h +++ b/src/mesa/swrast/s_depth.h @@ -49,7 +49,10 @@ _swrast_read_depth_span_float( struct gl_context *ctx, struct gl_renderbuffer *r GLint n, GLint x, GLint y, GLfloat depth[] ); extern void -_swrast_clear_depth_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb ); +_swrast_clear_depth_buffer(struct gl_context *ctx); + +extern void +_swrast_clear_depth_stencil_buffer(struct gl_context *ctx); #endif diff --git a/src/mesa/swrast/s_stencil.c b/src/mesa/swrast/s_stencil.c index 101ee505671..5f81fe8ec73 100644 --- a/src/mesa/swrast/s_stencil.c +++ b/src/mesa/swrast/s_stencil.c @@ -1124,121 +1124,107 @@ _swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y, /** - * Clear the stencil buffer. + * Clear the stencil buffer. If the buffer is a combined + * depth+stencil buffer, only the stencil bits will be touched. */ void -_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb ) +_swrast_clear_stencil_buffer(struct gl_context *ctx) { + struct gl_renderbuffer *rb = + ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; - const GLuint mask = ctx->Stencil.WriteMask[0]; - const GLuint invMask = ~mask; - const GLuint clearVal = (ctx->Stencil.Clear & mask); + const GLuint writeMask = ctx->Stencil.WriteMask[0]; const GLuint stencilMax = (1 << stencilBits) - 1; GLint x, y, width, height; + GLubyte *map; + GLint rowStride, i, j; + GLbitfield mapMode; - if (!rb || mask == 0) + if (!rb || writeMask == 0) return; - ASSERT(rb->DataType == GL_UNSIGNED_BYTE || - rb->DataType == GL_UNSIGNED_SHORT); - - ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX); - /* 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; - if (rb->GetPointer(ctx, rb, 0, 0)) { - /* Direct buffer access */ - if ((mask & stencilMax) != stencilMax) { - /* need to mask the clear */ - if (rb->DataType == GL_UNSIGNED_BYTE) { - GLint i, j; - for (i = 0; i < height; i++) { - GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i); - for (j = 0; j < width; j++) { - stencil[j] = (stencil[j] & invMask) | clearVal; - } - } - } - else { - GLint i, j; + mapMode = GL_MAP_WRITE_BIT; + if ((writeMask & stencilMax) != stencilMax) { + /* need to mask stencil values */ + mapMode |= GL_MAP_READ_BIT; + } + else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) { + /* combined depth+stencil, need to mask Z values */ + mapMode |= GL_MAP_READ_BIT; + } + + ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, + mapMode, &map, &rowStride); + if (!map) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)"); + return; + } + + switch (rb->Format) { + case MESA_FORMAT_S8: + { + GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff; + GLubyte mask = (~writeMask) & 0xff; + if (mask != 0) { + /* masked clear */ for (i = 0; i < height; i++) { - GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i); + GLubyte *row = map; for (j = 0; j < width; j++) { - stencil[j] = (stencil[j] & invMask) | clearVal; + row[j] = (row[j] & mask) | clear; } + map += rowStride; } } - } - else { - /* no bit masking */ - if (width == (GLint) rb->Width && rb->DataType == GL_UNSIGNED_BYTE) { - /* optimized case */ - /* Note: bottom-to-top raster assumed! */ - GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y); - GLuint len = width * height * sizeof(GLubyte); - memset(stencil, clearVal, len); + else if (rowStride == width) { + /* clear whole buffer */ + memset(map, clear, width * height); } else { - /* general case */ - GLint i; + /* clear scissored */ for (i = 0; i < height; i++) { - GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i); - if (rb->DataType == GL_UNSIGNED_BYTE) { - memset(stencil, clearVal, width); - } - else { - _mesa_memset16((short unsigned int*) stencil, clearVal, width); - } + memset(map, clear, width); + map += rowStride; } } } - } - else { - /* no direct access */ - if ((mask & stencilMax) != stencilMax) { - /* need to mask the clear */ - if (rb->DataType == GL_UNSIGNED_BYTE) { - GLint i, j; - for (i = 0; i < height; i++) { - GLubyte stencil[MAX_WIDTH]; - rb->GetRow(ctx, rb, width, x, y + i, stencil); - for (j = 0; j < width; j++) { - stencil[j] = (stencil[j] & invMask) | clearVal; - } - rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); - } - } - else { - GLint i, j; - for (i = 0; i < height; i++) { - GLushort stencil[MAX_WIDTH]; - rb->GetRow(ctx, rb, width, x, y + i, stencil); - for (j = 0; j < width; j++) { - stencil[j] = (stencil[j] & invMask) | clearVal; - } - rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); + break; + case MESA_FORMAT_S8_Z24: + { + GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24; + GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff; + for (i = 0; i < height; i++) { + GLuint *row = (GLuint *) map; + for (j = 0; j < width; j++) { + row[j] = (row[j] & mask) | clear; } + map += rowStride; } } - else { - /* no bit masking */ - const GLubyte clear8 = (GLubyte) clearVal; - const GLushort clear16 = (GLushort) clearVal; - const void *clear; - GLint i; - if (rb->DataType == GL_UNSIGNED_BYTE) { - clear = &clear8; - } - else { - clear = &clear16; - } + break; + case MESA_FORMAT_Z24_S8: + { + GLuint clear = ctx->Stencil.Clear & writeMask & 0xff; + GLuint mask = 0xffffff00 | ((~writeMask) & 0xff); for (i = 0; i < height; i++) { - rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL); + GLuint *row = (GLuint *) map; + for (j = 0; j < width; j++) { + row[j] = (row[j] & mask) | clear; + } + map += rowStride; } } + break; + default: + _mesa_problem(ctx, "Unexpected stencil buffer format %s" + " in _swrast_clear_stencil_buffer()", + _mesa_get_format_name(rb->Format)); } + + ctx->Driver.UnmapRenderbuffer(ctx, rb); } diff --git a/src/mesa/swrast/s_stencil.h b/src/mesa/swrast/s_stencil.h index 37f3c8da147..113649a375c 100644 --- a/src/mesa/swrast/s_stencil.h +++ b/src/mesa/swrast/s_stencil.h @@ -47,7 +47,7 @@ _swrast_write_stencil_span( struct gl_context *ctx, GLint n, GLint x, GLint y, extern void -_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb ); +_swrast_clear_stencil_buffer(struct gl_context *ctx); #endif -- 2.30.2