#include "utils.h"
-#define DRIVER_DATE "20051026"
+#define DRIVER_DATE "20051027"
/* Return the width and height of the current color buffer.
GLuint flags = 0;
GLint i;
GLint ret;
+ GLuint depthmask = 0;
if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
fprintf( stderr, "%s:\n", __FUNCTION__ );
if ( ( mask & BUFFER_BIT_DEPTH ) && ctx->Depth.Mask ) {
flags |= R128_DEPTH;
+ /* if we're at 16 bits, extra plane mask won't hurt */
+ depthmask |= 0x00ffffff;
mask &= ~BUFFER_BIT_DEPTH;
}
-#if 0
- /* FIXME: Add stencil support */
- if ( mask & BUFFER_BIT_STENCIL ) {
- flags |= DRM_R128_DEPTH_BUFFER;
+
+ if ( mask & BUFFER_BIT_STENCIL &&
+ (ctx->Visual.stencilBits > 0 && ctx->Visual.depthBits == 24) ) {
+ flags |= R128_DEPTH;
+ depthmask |= ctx->Stencil.WriteMask[0] << 24;
mask &= ~BUFFER_BIT_STENCIL;
}
-#endif
if ( flags ) {
clear.clear_color = rmesa->ClearColor;
clear.clear_depth = rmesa->ClearDepth;
clear.color_mask = rmesa->setup.plane_3d_mask_c;
- clear.depth_mask = ~0;
+ clear.depth_mask = depthmask;
ret = drmCommandWrite( rmesa->driFd, DRM_R128_CLEAR,
&clear, sizeof(clear) );
return GL_FALSE; /* not implemented */
}
else {
+ const GLboolean swDepth = GL_FALSE;
+ const GLboolean swAlpha = GL_FALSE;
+ const GLboolean swAccum = mesaVis->accumRedBits > 0;
+ const GLboolean swStencil = mesaVis->stencilBits > 0 &&
+ mesaVis->depthBits != 24;
struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
{
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
}
+ if (mesaVis->stencilBits > 0 && !swStencil) {
+ driRenderbuffer *stencilRb
+ = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT,
+ NULL,
+ screen->cpp,
+ screen->depthOffset, screen->depthPitch,
+ driDrawPriv);
+ r128SetSpanFunctions(stencilRb, mesaVis);
+ _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base);
+ }
+
_mesa_add_soft_renderbuffers(fb,
GL_FALSE, /* color */
- GL_FALSE, /* depth */
- mesaVis->stencilBits > 0,
- mesaVis->accumRedBits > 0,
- GL_FALSE, /* alpha */
+ swDepth,
+ swStencil,
+ swAccum,
+ swAlpha,
GL_FALSE /* aux */);
driDrawPriv->driverPrivate = (void *) fb;
#define HAVE_HW_DEPTH_SPANS 1
#define HAVE_HW_DEPTH_PIXELS 1
+#define HAVE_HW_STENCIL_SPANS 1
+#define HAVE_HW_STENCIL_PIXELS 1
#define LOCAL_VARS \
r128ContextPtr rmesa = R128_CONTEXT(ctx); \
+ ((dPriv->y + (Y)) * drb->flippedPitch + (dPriv->x + (X))) * drb->cpp)
#include "spantmp2.h"
+/* Idling in the depth/stencil span functions:
+ * For writes, the kernel reads from the given user-space buffer at dispatch
+ * time, and then writes to the depth buffer asynchronously.
+ * For reads, the kernel reads from the depth buffer and writes to the span
+ * temporary asynchronously.
+ * So, if we're going to read from the span temporary, we need to idle before
+ * doing so. But we don't need to idle after write, because the CPU won't
+ * be accessing the destination, only the accelerator (through 3d rendering or
+ * depth span reads)
+ * However, due to interactions from pixel cache between 2d (what we do with
+ * depth) and 3d (all other parts of the system), we idle at the begin and end
+ * of a set of span operations, which should cover the pix cache issue.
+ * Except, we still have major issues, as shown by no_rast=true glxgears, or
+ * stencilwrap.
+ */
/* ================================================================
* Depth buffer
*/
#define WRITE_DEPTH_SPAN() \
+do { \
r128WriteDepthSpanLocked( rmesa, n, \
x + dPriv->x, \
y + dPriv->y, \
- depth, mask );
+ depth, mask ); \
+} while (0)
#define WRITE_DEPTH_PIXELS() \
do { \
/* 24-bit depth, 8-bit stencil buffer functions
*/
#define WRITE_DEPTH_SPAN() \
+do { \
+ GLint buf[n]; \
+ GLint i; \
+ GLuint *readbuf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ r128ReadDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y ); \
+ r128WaitForIdleLocked( rmesa ); \
+ for ( i = 0 ; i < n ; i++ ) { \
+ buf[i] = (readbuf[i] & 0xff000000) | (depth[i] & 0x00ffffff); \
+ } \
r128WriteDepthSpanLocked( rmesa, n, \
x + dPriv->x, \
y + dPriv->y, \
- depth, mask );
+ buf, mask ); \
+} while (0)
#define WRITE_DEPTH_PIXELS() \
do { \
+ GLint buf[n]; \
GLint ox[MAX_WIDTH]; \
GLint oy[MAX_WIDTH]; \
+ GLuint *readbuf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
for ( i = 0 ; i < n ; i++ ) { \
ox[i] = x[i] + dPriv->x; \
oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
} \
- r128WriteDepthPixelsLocked( rmesa, n, ox, oy, depth, mask ); \
+ r128ReadDepthPixelsLocked( rmesa, n, ox, oy ); \
+ r128WaitForIdleLocked( rmesa ); \
+ for ( i = 0 ; i < n ; i++ ) { \
+ buf[i] = (readbuf[i] & 0xff000000) | (depth[i] & 0x00ffffff); \
+ } \
+ r128WriteDepthPixelsLocked( rmesa, n, ox, oy, buf, mask ); \
} while (0)
#define READ_DEPTH_SPAN() \
r128scrn->spanOffset); \
GLint i; \
\
+ /*if (n >= 128) fprintf(stderr, "Large number of pixels: %d\n", n);*/ \
r128ReadDepthSpanLocked( rmesa, n, \
x + dPriv->x, \
y + dPriv->y ); \
* Stencil buffer
*/
-/* FIXME: Add support for hardware stencil buffers.
+/* 24 bit depth, 8 bit stencil depthbuffer functions
*/
+#define WRITE_STENCIL_SPAN() \
+do { \
+ GLint buf[n]; \
+ GLint i; \
+ GLuint *readbuf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ r128ReadDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y ); \
+ r128WaitForIdleLocked( rmesa ); \
+ for ( i = 0 ; i < n ; i++ ) { \
+ buf[i] = (readbuf[i] & 0x00ffffff) | (stencil[i] << 24); \
+ } \
+ r128WriteDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y, \
+ buf, mask ); \
+} while (0)
+
+#define WRITE_STENCIL_PIXELS() \
+do { \
+ GLint buf[n]; \
+ GLint ox[MAX_WIDTH]; \
+ GLint oy[MAX_WIDTH]; \
+ GLuint *readbuf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ for ( i = 0 ; i < n ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ r128ReadDepthPixelsLocked( rmesa, n, ox, oy ); \
+ r128WaitForIdleLocked( rmesa ); \
+ for ( i = 0 ; i < n ; i++ ) { \
+ buf[i] = (readbuf[i] & 0x00ffffff) | (stencil[i] << 24); \
+ } \
+ r128WriteDepthPixelsLocked( rmesa, n, ox, oy, buf, mask ); \
+} while (0)
+
+#define READ_STENCIL_SPAN() \
+do { \
+ GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i; \
+ \
+ /*if (n >= 128) fprintf(stderr, "Large number of pixels: %d\n", n);*/ \
+ r128ReadDepthSpanLocked( rmesa, n, \
+ x + dPriv->x, \
+ y + dPriv->y ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < n ; i++ ) { \
+ stencil[i] = (buf[i] & 0xff000000) >> 24; \
+ } \
+} while (0)
+
+#define READ_STENCIL_PIXELS() \
+do { \
+ GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \
+ r128scrn->spanOffset); \
+ GLint i, remaining = n; \
+ \
+ while ( remaining > 0 ) { \
+ GLint ox[128]; \
+ GLint oy[128]; \
+ GLint count; \
+ \
+ if ( remaining <= 128 ) { \
+ count = remaining; \
+ } else { \
+ count = 128; \
+ } \
+ for ( i = 0 ; i < count ; i++ ) { \
+ ox[i] = x[i] + dPriv->x; \
+ oy[i] = Y_FLIP( y[i] ) + dPriv->y; \
+ } \
+ \
+ r128ReadDepthPixelsLocked( rmesa, count, ox, oy ); \
+ r128WaitForIdleLocked( rmesa ); \
+ \
+ for ( i = 0 ; i < count ; i++ ) { \
+ stencil[i] = (buf[i] & 0xff000000) >> 24; \
+ } \
+ stencil += count; \
+ x += count; \
+ y += count; \
+ remaining -= count; \
+ } \
+} while (0)
+
+#define TAG(x) radeon##x##_z24_s8
+#include "stenciltmp.h"
static void
r128SpanRenderStart( GLcontext *ctx )
{
r128ContextPtr rmesa = R128_CONTEXT(ctx);
_swrast_flush( ctx );
+ r128WaitForIdleLocked( rmesa );
UNLOCK_HARDWARE( rmesa );
}
else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT24) {
r128InitDepthPointers_z24_s8(&drb->Base);
}
+ else if (drb->Base.InternalFormat == GL_STENCIL_INDEX8_EXT) {
+ radeonInitStencilPointers_z24_s8(&drb->Base);
+ }
}
rmesa->new_state |= R128_NEW_ALPHA;
}
+/* =============================================================
+ * Stencil
+ */
+
+static void
+r128DDStencilFuncSeparate( GLcontext *ctx, GLenum face, GLenum func,
+ GLint ref, GLuint mask )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint refmask = ((ctx->Stencil.Ref[0] << 0) |
+ (ctx->Stencil.ValueMask[0] << 16) |
+ (ctx->Stencil.WriteMask[0] << 24));
+ GLuint z = rmesa->setup.z_sten_cntl_c;
+
+ z &= ~R128_STENCIL_TEST_MASK;
+ switch ( ctx->Stencil.Function[0] ) {
+ case GL_NEVER:
+ z |= R128_STENCIL_TEST_NEVER;
+ break;
+ case GL_LESS:
+ z |= R128_STENCIL_TEST_LESS;
+ break;
+ case GL_EQUAL:
+ z |= R128_STENCIL_TEST_EQUAL;
+ break;
+ case GL_LEQUAL:
+ z |= R128_STENCIL_TEST_LESSEQUAL;
+ break;
+ case GL_GREATER:
+ z |= R128_STENCIL_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ z |= R128_STENCIL_TEST_NEQUAL;
+ break;
+ case GL_GEQUAL:
+ z |= R128_STENCIL_TEST_GREATEREQUAL;
+ break;
+ case GL_ALWAYS:
+ z |= R128_STENCIL_TEST_ALWAYS;
+ break;
+ }
+
+ if ( rmesa->setup.sten_ref_mask_c != refmask ) {
+ rmesa->setup.sten_ref_mask_c = refmask;
+ rmesa->dirty |= R128_UPLOAD_MASKS;
+ }
+ if ( rmesa->setup.z_sten_cntl_c != z ) {
+ rmesa->setup.z_sten_cntl_c = z;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+}
+
+static void
+r128DDStencilMaskSeparate( GLcontext *ctx, GLenum face, GLuint mask )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint refmask = ((ctx->Stencil.Ref[0] << 0) |
+ (ctx->Stencil.ValueMask[0] << 16) |
+ (ctx->Stencil.WriteMask[0] << 24));
+
+ if ( rmesa->setup.sten_ref_mask_c != refmask ) {
+ rmesa->setup.sten_ref_mask_c = refmask;
+ rmesa->dirty |= R128_UPLOAD_MASKS;
+ }
+}
+
+static void r128DDStencilOpSeparate( GLcontext *ctx, GLenum face, GLenum fail,
+ GLenum zfail, GLenum zpass )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+ GLuint z = rmesa->setup.z_sten_cntl_c;
+ GLboolean ok = 1;
+
+ if (!( ctx->Visual.stencilBits > 0 && ctx->Visual.depthBits == 24 ))
+ return;
+
+ z &= ~(R128_STENCIL_S_FAIL_MASK | R128_STENCIL_ZPASS_MASK |
+ R128_STENCIL_ZFAIL_MASK);
+
+ switch ( ctx->Stencil.FailFunc[0] ) {
+ case GL_KEEP:
+ z |= R128_STENCIL_S_FAIL_KEEP;
+ break;
+ case GL_ZERO:
+ z |= R128_STENCIL_S_FAIL_ZERO;
+ ok = 0; /* Hardware bug? ZERO maps to KEEP */
+ break;
+ case GL_REPLACE:
+ z |= R128_STENCIL_S_FAIL_REPLACE;
+ ok = 0; /* Hardware bug? REPLACE maps to KEEP */
+ break;
+ case GL_INCR:
+ z |= R128_STENCIL_S_FAIL_INC;
+ break;
+ case GL_DECR:
+ z |= R128_STENCIL_S_FAIL_DEC;
+ break;
+ case GL_INVERT:
+ z |= R128_STENCIL_S_FAIL_INV;
+ ok = 0; /* Hardware bug? INV maps to ZERO */
+ break;
+ }
+
+ switch ( ctx->Stencil.ZFailFunc[0] ) {
+ case GL_KEEP:
+ z |= R128_STENCIL_ZFAIL_KEEP;
+ ok = 0; /* Hardware bug? KEEP maps to ZERO */
+ break;
+ case GL_ZERO:
+ z |= R128_STENCIL_ZFAIL_ZERO;
+ break;
+ case GL_REPLACE:
+ z |= R128_STENCIL_ZFAIL_REPLACE;
+ break;
+ case GL_INCR:
+ z |= R128_STENCIL_ZFAIL_INC;
+ break;
+ case GL_DECR:
+ z |= R128_STENCIL_ZFAIL_DEC;
+ break;
+ case GL_INVERT:
+ z |= R128_STENCIL_ZFAIL_INV;
+ ok = 0; /* Hardware bug? INV maps to ZERO */
+ break;
+ }
+
+ switch ( ctx->Stencil.ZPassFunc[0] ) {
+ case GL_KEEP:
+ z |= R128_STENCIL_ZPASS_KEEP;
+ ok = 0; /* Hardware bug? KEEP maps to ZERO */
+ break;
+ case GL_ZERO:
+ z |= R128_STENCIL_ZPASS_ZERO;
+ break;
+ case GL_REPLACE:
+ z |= R128_STENCIL_ZPASS_REPLACE;
+ break;
+ case GL_INCR:
+ z |= R128_STENCIL_ZPASS_INC;
+ break;
+ case GL_DECR:
+ z |= R128_STENCIL_ZPASS_DEC;
+ ok = 0; /* Hardware bug? DEC maps to INCR_WRAP */
+ break;
+ case GL_INVERT:
+ z |= R128_STENCIL_ZPASS_INV;
+ ok = 0; /* Hardware bug? INV maps to ZERO */
+ break;
+ }
+
+ /* XXX: Now that we know whether we can do the given funcs successfully
+ * (according to testing done with a modified stencilwrap test), go
+ * ahead and drop that knowledge on the floor. While fallbacks remain
+ * broken, they make the situation even worse (in test apps, at least) than
+ * failing in just the stencil part.
+ */
+ /*FALLBACK( rmesa, R128_FALLBACK_STENCIL, !ok );*/
+
+ if ( rmesa->setup.z_sten_cntl_c != z ) {
+ rmesa->setup.z_sten_cntl_c = z;
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ }
+}
+
+static void r128DDClearStencil( GLcontext *ctx, GLint s )
+{
+ r128ContextPtr rmesa = R128_CONTEXT(ctx);
+
+ if (ctx->Visual.stencilBits > 0 && ctx->Visual.depthBits == 24) {
+ rmesa->ClearDepth &= 0x00ffffff;
+ rmesa->ClearDepth |= ctx->Stencil.Clear << 24;
+ }
+}
/* =============================================================
* Depth testing
break;
case R128_Z_PIX_WIDTH_24:
rmesa->ClearDepth = d * 0x00ffffff;
+ rmesa->ClearDepth |= ctx->Stencil.Clear << 24;
break;
case R128_Z_PIX_WIDTH_32:
rmesa->ClearDepth = d * 0xffffffff;
case GL_STENCIL_TEST:
FLUSH_BATCH( rmesa );
- FALLBACK( rmesa, R128_FALLBACK_STENCIL, state );
+ if ( ctx->Visual.stencilBits > 0 && ctx->Visual.depthBits == 24 ) {
+ if ( state ) {
+ rmesa->setup.tex_cntl_c |= R128_STENCIL_ENABLE;
+ /* Reset the fallback (if any) for bad stencil funcs */
+ r128DDStencilOpSeparate( ctx, 0, ctx->Stencil.FailFunc[0],
+ ctx->Stencil.ZFailFunc[0],
+ ctx->Stencil.ZPassFunc[0] );
+ } else {
+ rmesa->setup.tex_cntl_c &= ~R128_STENCIL_ENABLE;
+ FALLBACK( rmesa, R128_FALLBACK_STENCIL, GL_FALSE );
+ }
+ rmesa->dirty |= R128_UPLOAD_CONTEXT;
+ } else {
+ FALLBACK( rmesa, R128_FALLBACK_STENCIL, state );
+ }
break;
case GL_TEXTURE_1D:
ctx->Driver.ClearIndex = NULL;
ctx->Driver.ClearColor = r128DDClearColor;
+ ctx->Driver.ClearStencil = r128DDClearStencil;
ctx->Driver.DrawBuffer = r128DDDrawBuffer;
ctx->Driver.ReadBuffer = r128DDReadBuffer;
ctx->Driver.RenderMode = r128DDRenderMode;
ctx->Driver.Scissor = r128DDScissor;
ctx->Driver.ShadeModel = r128DDShadeModel;
+ ctx->Driver.StencilFuncSeparate = r128DDStencilFuncSeparate;
+ ctx->Driver.StencilMaskSeparate = r128DDStencilMaskSeparate;
+ ctx->Driver.StencilOpSeparate = r128DDStencilOpSeparate;
ctx->Driver.DepthRange = r128DepthRange;
ctx->Driver.Viewport = r128Viewport;
# define R128_STENCIL_TEST_GREATER (5 << 12)
# define R128_STENCIL_TEST_NEQUAL (6 << 12)
# define R128_STENCIL_TEST_ALWAYS (7 << 12)
+# define R128_STENCIL_TEST_MASK (7 << 12)
# define R128_STENCIL_S_FAIL_KEEP (0 << 16)
# define R128_STENCIL_S_FAIL_ZERO (1 << 16)
# define R128_STENCIL_S_FAIL_REPLACE (2 << 16)
# define R128_STENCIL_S_FAIL_INC (3 << 16)
# define R128_STENCIL_S_FAIL_DEC (4 << 16)
# define R128_STENCIL_S_FAIL_INV (5 << 16)
+# define R128_STENCIL_S_FAIL_MASK (7 << 16)
# define R128_STENCIL_ZPASS_KEEP (0 << 20)
# define R128_STENCIL_ZPASS_ZERO (1 << 20)
# define R128_STENCIL_ZPASS_REPLACE (2 << 20)
# define R128_STENCIL_ZPASS_INC (3 << 20)
# define R128_STENCIL_ZPASS_DEC (4 << 20)
# define R128_STENCIL_ZPASS_INV (5 << 20)
+# define R128_STENCIL_ZPASS_MASK (7 << 20)
# define R128_STENCIL_ZFAIL_KEEP (0 << 24)
# define R128_STENCIL_ZFAIL_ZERO (1 << 24)
# define R128_STENCIL_ZFAIL_REPLACE (2 << 24)
# define R128_STENCIL_ZFAIL_INC (3 << 24)
# define R128_STENCIL_ZFAIL_DEC (4 << 24)
# define R128_STENCIL_ZFAIL_INV (5 << 24)
+# define R128_STENCIL_ZFAIL_MASK (7 << 24)
#define R128_TEX_CNTL_C 0x1c9c
# define R128_Z_ENABLE (1 << 0)
# define R128_Z_WRITE_ENABLE (1 << 1)