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 <jfonseca@vmware.com>
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 =
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);
}
#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"
}
}
+
/**
- * 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 */
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);
+
}
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
/**
- * 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);
}
extern void
-_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb );
+_swrast_clear_stencil_buffer(struct gl_context *ctx);
#endif