radeon: add support for new dri2 interfaces & fix single buffer rendering
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_common.c
index 5c34ca89fab2591b98b223450d2532c70f9539de..decea4518e6c50f5b3f6facefc40215d899e831c 100644 (file)
@@ -58,6 +58,22 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "tnl/t_pipeline.h"
 #include "swrast_setup/swrast_setup.h"
 
+#include "main/blend.h"
+#include "main/bufferobj.h"
+#include "main/buffers.h"
+#include "main/depth.h"
+#include "main/polygon.h"
+#include "main/shaders.h"
+#include "main/texstate.h"
+#include "main/varray.h"
+#include "glapi/dispatch.h"
+#include "swrast/swrast.h"
+#include "main/stencil.h"
+#include "main/matrix.h"
+#include "main/attrib.h"
+#include "main/enable.h"
+#include "main/viewport.h"
+
 #include "dri_util.h"
 #include "vblank.h"
 
@@ -132,10 +148,10 @@ void radeonRecalcScissorRects(radeonContextPtr radeon)
        }
 }
 
-static void radeon_get_cliprects(radeonContextPtr radeon,
-                                struct drm_clip_rect **cliprects,
-                                unsigned int *num_cliprects,
-                                int *x_off, int *y_off)
+void radeon_get_cliprects(radeonContextPtr radeon,
+                         struct drm_clip_rect **cliprects,
+                         unsigned int *num_cliprects,
+                         int *x_off, int *y_off)
 {
        __DRIdrawablePrivate *dPriv = radeon->dri.drawable;
        struct radeon_framebuffer *rfb = dPriv->driverPrivate;
@@ -245,7 +261,7 @@ static uint32_t radeonGetLastFrame(radeonContextPtr radeon)
 {
        drm_radeon_getparam_t gp;
        int ret;
-       uint32_t frame;
+       uint32_t frame = 0;
 
        gp.param = RADEON_PARAM_LAST_FRAME;
        gp.value = (int *)&frame;
@@ -362,9 +378,11 @@ void radeonWaitForIdleLocked(radeonContextPtr radeon)
 
 static void radeonWaitForIdle(radeonContextPtr radeon)
 {
-       LOCK_HARDWARE(radeon);
-       radeonWaitForIdleLocked(radeon);
-       UNLOCK_HARDWARE(radeon);
+       if (!radeon->radeonScreen->driScreen->dri2.enabled) {
+        LOCK_HARDWARE(radeon);
+           radeonWaitForIdleLocked(radeon);
+           UNLOCK_HARDWARE(radeon);
+    }
 }
 
 static void radeon_flip_renderbuffers(struct radeon_framebuffer *rfb)
@@ -619,6 +637,7 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
        radeonContextPtr radeon = RADEON_CONTEXT(ctx);
        struct radeon_renderbuffer *rrbDepth = NULL, *rrbStencil = NULL,
                *rrbColor = NULL;
+       uint32_t offset = 0;
        
 
        if (!fb) {
@@ -657,17 +676,21 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
                /* none */
        if (fb->Name == 0) {
                if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) {
-                       rrbColor = (void *)fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+                       rrbColor = radeon_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
                        radeon->front_cliprects = GL_TRUE;
+                       radeon->front_buffer_dirty = GL_TRUE;
                } else {
-                       rrbColor = (void *)fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
+                       rrbColor = radeon_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
                        radeon->front_cliprects = GL_FALSE;
                }
        } else {
                /* user FBO in theory */
                struct radeon_renderbuffer *rrb;
-               rrb = (void *)fb->_ColorDrawBuffers[0];
-               rrbColor = rrb;
+               rrb = radeon_renderbuffer(fb->_ColorDrawBuffers[0]);
+               if (rrb) {
+                       offset = rrb->draw_offset;
+                       rrbColor = rrb;
+               }
                radeon->constant_cliprect = GL_TRUE;
        }
 
@@ -677,9 +700,8 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
                radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE);
 
 
-
        if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
-               rrbDepth = (struct radeon_renderbuffer *)fb->_DepthBuffer->Wrapped;
+               rrbDepth = radeon_renderbuffer(fb->_DepthBuffer->Wrapped);
                if (rrbDepth && rrbDepth->bo) {
                        radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DEPTH_BUFFER, GL_FALSE);
                } else {
@@ -690,16 +712,11 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
                rrbDepth = NULL;
        }
 
-       /* TODO stencil things */
        if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
-               rrbStencil = (struct radeon_renderbuffer *)fb->_DepthBuffer->Wrapped;
+               rrbStencil = radeon_renderbuffer(fb->_DepthBuffer->Wrapped);
                if (rrbStencil && rrbStencil->bo) {
                        radeon->vtbl.fallback(ctx, RADEON_FALLBACK_STENCIL_BUFFER, GL_FALSE);
                        /* need to re-compute stencil hw state */
-                       if (ctx->Driver.Enable != NULL)
-                               ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
-                       else
-                               ctx->NewState |= _NEW_STENCIL;
                        if (!rrbDepth)
                                rrbDepth = rrbStencil;
                } else {
@@ -725,26 +742,28 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
         * Update depth test state
         */
        if (ctx->Driver.Enable) {
-               if (ctx->Depth.Test && fb->Visual.depthBits > 0) {
-                       ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_TRUE);
-               } else {
-                       ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_FALSE);
-               }
+               ctx->Driver.Enable(ctx, GL_DEPTH_TEST,
+                                  (ctx->Depth.Test && fb->Visual.depthBits > 0));
+               ctx->Driver.Enable(ctx, GL_STENCIL_TEST,
+                                  (ctx->Stencil._Enabled && fb->Visual.stencilBits > 0));
        } else {
-               ctx->NewState |= _NEW_DEPTH;
+               ctx->NewState |= (_NEW_DEPTH | _NEW_STENCIL);
        }
        
        radeon->state.depth.rrb = rrbDepth;
-
        radeon->state.color.rrb = rrbColor;
+       radeon->state.color.draw_offset = offset;
 
+#if 0
        /* update viewport since it depends on window size */
        if (ctx->Driver.Viewport) {
                ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
                                     ctx->Viewport.Width, ctx->Viewport.Height);
        } else {
-               ctx->NewState |= _NEW_VIEWPORT;
+       
        }
+#endif
+       ctx->NewState |= _NEW_VIEWPORT;
 
        /* Set state we know depends on drawable parameters:
         */
@@ -752,6 +771,19 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
                ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
                                    ctx->Scissor.Width, ctx->Scissor.Height);
        radeon->NewGLState |= _NEW_SCISSOR;
+
+       if (ctx->Driver.DepthRange)
+               ctx->Driver.DepthRange(ctx,
+                                      ctx->Viewport.Near,
+                                      ctx->Viewport.Far);
+
+       /* Update culling direction which changes depending on the
+        * orientation of the buffer:
+        */
+       if (ctx->Driver.FrontFace)
+               ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
+       else
+               ctx->NewState |= _NEW_POLYGON;
 }
 
 /**
@@ -759,13 +791,27 @@ void radeon_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
  */
 void radeonDrawBuffer( GLcontext *ctx, GLenum mode )
 {
-       radeonContextPtr radeon = RADEON_CONTEXT(ctx);
-       
        if (RADEON_DEBUG & DEBUG_DRI)
                fprintf(stderr, "%s %s\n", __FUNCTION__,
                        _mesa_lookup_enum_by_nr( mode ));
-       
-       radeon_firevertices(radeon);    /* don't pipeline cliprect changes */
+
+       if (ctx->DrawBuffer->Name == 0) {
+               radeonContextPtr radeon = RADEON_CONTEXT(ctx);
+
+               const GLboolean was_front_buffer_rendering =
+                       radeon->is_front_buffer_rendering;
+
+               radeon->is_front_buffer_rendering = (mode == GL_FRONT_LEFT) ||
+                                            (mode == GL_FRONT);
+
+      /* If we weren't front-buffer rendering before but we are now, make sure
+       * that the front-buffer has actually been allocated.
+       */
+               if (!was_front_buffer_rendering && radeon->is_front_buffer_rendering) {
+                       radeon_update_renderbuffers(radeon->dri.context,
+                               radeon->dri.context->driDrawablePriv);
+      }
+       }
        
        radeon_draw_buffer(ctx, ctx->DrawBuffer);
 }
@@ -799,10 +845,6 @@ void radeonUpdatePageFlipping(radeonContextPtr radeon)
 
 void radeon_window_moved(radeonContextPtr radeon)
 {
-       GLcontext *ctx = radeon->glCtx;
-       __DRIdrawablePrivate *dPriv = radeon->dri.drawable;
-       struct radeon_framebuffer *rfb = dPriv->driverPrivate;
-
        if (!radeon->radeonScreen->driScreen->dri2.enabled) {
                radeonUpdatePageFlipping(radeon);
        }
@@ -829,20 +871,57 @@ void radeon_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei he
        radeon_window_moved(radeon);
        radeon_draw_buffer(ctx, radeon->glCtx->DrawBuffer);
        ctx->Driver.Viewport = old_viewport;
-
-
 }
-static void radeon_print_state_atom(radeonContextPtr radeon, struct radeon_state_atom *state )
-{
-       int i;
-       int dwords = (*state->check)(radeon->glCtx, state);
-
-       fprintf(stderr, "emit %s %d/%d\n", state->name, state->cmd_size, dwords);
 
-       if (RADEON_DEBUG & DEBUG_VERBOSE) 
-               for (i = 0 ; i < dwords; i++) 
-                       fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]);
+static void radeon_print_state_atom(radeonContextPtr radeon, struct radeon_state_atom *state)
+{
+       int i, j, reg;
+       int dwords = (*state->check) (radeon->glCtx, state);
+       drm_r300_cmd_header_t cmd;
+
+       fprintf(stderr, "  emit %s %d/%d\n", state->name, dwords, state->cmd_size);
+
+       if (RADEON_DEBUG & DEBUG_VERBOSE) {
+               for (i = 0; i < dwords;) {
+                       cmd = *((drm_r300_cmd_header_t *) &state->cmd[i]);
+                       reg = (cmd.packet0.reghi << 8) | cmd.packet0.reglo;
+                       fprintf(stderr, "      %s[%d]: cmdpacket0 (first reg=0x%04x, count=%d)\n",
+                                       state->name, i, reg, cmd.packet0.count);
+                       ++i;
+                       for (j = 0; j < cmd.packet0.count && i < dwords; j++) {
+                               fprintf(stderr, "      %s[%d]: 0x%04x = %08x\n",
+                                               state->name, i, reg, state->cmd[i]);
+                               reg += 4;
+                               ++i;
+                       }
+               }
+       }
+}
 
+static void radeon_print_state_atom_kmm(radeonContextPtr radeon, struct radeon_state_atom *state)
+{
+       int i, j, reg, count;
+       int dwords = (*state->check) (radeon->glCtx, state);
+       uint32_t packet0;
+
+       fprintf(stderr, "  emit %s %d/%d\n", state->name, dwords, state->cmd_size);
+
+       if (RADEON_DEBUG & DEBUG_VERBOSE) {
+               for (i = 0; i < dwords;) {
+                       packet0 = state->cmd[i];
+                       reg = (packet0 & 0x1FFF) << 2;
+                       count = ((packet0 & 0x3FFF0000) >> 16) + 1;
+                       fprintf(stderr, "      %s[%d]: cmdpacket0 (first reg=0x%04x, count=%d)\n",
+                                       state->name, i, reg, count);
+                       ++i;
+                       for (j = 0; j < count && i < dwords; j++) {
+                               fprintf(stderr, "      %s[%d]: 0x%04x = %08x\n",
+                                               state->name, i, reg, state->cmd[i]);
+                               reg += 4;
+                               ++i;
+                       }
+               }
+       }
 }
 
 static INLINE void radeonEmitAtoms(radeonContextPtr radeon, GLboolean dirty)
@@ -860,7 +939,10 @@ static INLINE void radeonEmitAtoms(radeonContextPtr radeon, GLboolean dirty)
                        dwords = (*atom->check) (radeon->glCtx, atom);
                        if (dwords) {
                                if (DEBUG_CMDBUF && RADEON_DEBUG & DEBUG_STATE) {
-                                       radeon_print_state_atom(radeon, atom);
+                                       if (radeon->radeonScreen->kernel_mm)
+                                               radeon_print_state_atom_kmm(radeon, atom);
+                                       else
+                                               radeon_print_state_atom(radeon, atom);
                                }
                                if (atom->emit) {
                                        (*atom->emit)(radeon->glCtx, atom);
@@ -882,6 +964,51 @@ static INLINE void radeonEmitAtoms(radeonContextPtr radeon, GLboolean dirty)
        COMMIT_BATCH();
 }
 
+GLboolean radeon_revalidate_bos(GLcontext *ctx)
+{
+       radeonContextPtr radeon = RADEON_CONTEXT(ctx);
+       int flushed = 0;
+       int ret;
+again:
+       ret = radeon_cs_space_check(radeon->cmdbuf.cs, radeon->state.bos, radeon->state.validated_bo_count);
+       if (ret == RADEON_CS_SPACE_OP_TO_BIG)
+               return GL_FALSE;
+       if (ret == RADEON_CS_SPACE_FLUSH) {
+               radeonFlush(ctx);
+               if (flushed)
+                       return GL_FALSE;
+               flushed = 1;
+               goto again;
+       }
+       return GL_TRUE;
+}
+
+void radeon_validate_reset_bos(radeonContextPtr radeon)
+{
+       int i;
+
+       for (i = 0; i < radeon->state.validated_bo_count; i++) {
+               radeon_bo_unref(radeon->state.bos[i].bo);
+               radeon->state.bos[i].bo = NULL;
+               radeon->state.bos[i].read_domains = 0;
+               radeon->state.bos[i].write_domain = 0;
+               radeon->state.bos[i].new_accounted = 0;
+       }
+       radeon->state.validated_bo_count = 0;
+}
+
+void radeon_validate_bo(radeonContextPtr radeon, struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
+{
+       radeon_bo_ref(bo);
+       radeon->state.bos[radeon->state.validated_bo_count].bo = bo;
+       radeon->state.bos[radeon->state.validated_bo_count].read_domains = read_domains;
+       radeon->state.bos[radeon->state.validated_bo_count].write_domain = write_domain;
+       radeon->state.bos[radeon->state.validated_bo_count].new_accounted = 0;
+       radeon->state.validated_bo_count++;
+
+       assert(radeon->state.validated_bo_count < RADEON_MAX_BOS);
+}
+
 void radeonEmitState(radeonContextPtr radeon)
 {
        if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS))
@@ -923,6 +1050,14 @@ void radeonFlush(GLcontext *ctx)
        if (RADEON_DEBUG & DEBUG_IOCTL)
                fprintf(stderr, "%s %d\n", __FUNCTION__, radeon->cmdbuf.cs->cdw);
 
+       /* okay if we have no cmds in the buffer &&
+          we have no DMA flush &&
+          we have no DMA buffer allocated.
+          then no point flushing anything at all.
+       */
+       if (!radeon->dma.flush && !radeon->cmdbuf.cs->cdw && !radeon->dma.current)
+               return;
+
        if (radeon->dma.flush)
                radeon->dma.flush( ctx );
 
@@ -930,6 +1065,26 @@ void radeonFlush(GLcontext *ctx)
    
        if (radeon->cmdbuf.cs->cdw)
                rcommonFlushCmdBuf(radeon, __FUNCTION__);
+
+       if ((ctx->DrawBuffer->Name == 0) && radeon->front_buffer_dirty) {
+               __DRIscreen *const screen = radeon->radeonScreen->driScreen;
+
+               if (screen->dri2.loader && (screen->dri2.loader->base.version >= 2)
+                       && (screen->dri2.loader->flushFrontBuffer != NULL)) {
+                       (*screen->dri2.loader->flushFrontBuffer)(radeon->dri.drawable,
+                                                 radeon->dri.drawable->loaderPrivate);
+
+                       /* Only clear the dirty bit if front-buffer rendering is no longer
+                        * enabled.  This is done so that the dirty bit can only be set in
+                        * glDrawBuffer.  Otherwise the dirty bit would have to be set at
+                        * each of N places that do rendering.  This has worse performances,
+                        * but it is much easier to get correct.
+                        */
+                       if (radeon->is_front_buffer_rendering) {
+                               radeon->front_buffer_dirty = GL_FALSE;
+                       }
+               }
+       }
 }
 
 /* Make sure all commands have been sent to the hardware and have
@@ -946,8 +1101,14 @@ void radeonFinish(GLcontext * ctx)
        if (radeon->radeonScreen->kernel_mm) {
                for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
                        struct radeon_renderbuffer *rrb;
-                       rrb = (struct radeon_renderbuffer *)fb->_ColorDrawBuffers[i];
-                       if (rrb->bo)
+                       rrb = radeon_renderbuffer(fb->_ColorDrawBuffers[i]);
+                       if (rrb && rrb->bo)
+                               radeon_bo_wait(rrb->bo);
+               }
+               {
+                       struct radeon_renderbuffer *rrb;
+                       rrb = radeon_get_depthbuffer(radeon);
+                       if (rrb && rrb->bo)
                                radeon_bo_wait(rrb->bo);
                }
        } else if (radeon->do_irqs) {
@@ -985,6 +1146,11 @@ int rcommonFlushCmdBufLocked(radeonContextPtr rmesa, const char *caller)
        }
        radeon_cs_erase(rmesa->cmdbuf.cs);
        rmesa->cmdbuf.flushing = 0;
+
+       if (radeon_revalidate_bos(rmesa->glCtx) == GL_FALSE) {
+               fprintf(stderr,"failed to revalidate buffers\n");
+       }
+
        return ret;
 }
 
@@ -1060,11 +1226,11 @@ void rcommonInitCmdBuf(radeonContextPtr rmesa)
                radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, rmesa->radeonScreen->texSize[0]);
                radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, rmesa->radeonScreen->gartTextures.size);
        } else {
-               struct drm_radeon_gem_info mminfo;
+               struct drm_radeon_gem_info mminfo = { 0 };
 
                if (!drmCommandWriteRead(rmesa->dri.fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
                {
-                       radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_size);
+                       radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_visible);
                        radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, mminfo.gart_size);
                }
        }
@@ -1105,3 +1271,226 @@ void rcommonBeginBatch(radeonContextPtr rmesa, int n,
 
 
 
+static void
+radeon_meta_set_passthrough_transform(radeonContextPtr radeon)
+{
+   GLcontext *ctx = radeon->glCtx;
+
+   radeon->meta.saved_vp_x = ctx->Viewport.X;
+   radeon->meta.saved_vp_y = ctx->Viewport.Y;
+   radeon->meta.saved_vp_width = ctx->Viewport.Width;
+   radeon->meta.saved_vp_height = ctx->Viewport.Height;
+   radeon->meta.saved_matrix_mode = ctx->Transform.MatrixMode;
+
+   _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
+
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+   _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1);
+
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+}
+
+static void
+radeon_meta_restore_transform(radeonContextPtr radeon)
+{
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PopMatrix();
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PopMatrix();
+
+   _mesa_MatrixMode(radeon->meta.saved_matrix_mode);
+
+   _mesa_Viewport(radeon->meta.saved_vp_x, radeon->meta.saved_vp_y,
+                 radeon->meta.saved_vp_width, radeon->meta.saved_vp_height);
+}
+
+
+/**
+ * Perform glClear where mask contains only color, depth, and/or stencil.
+ *
+ * The implementation is based on calling into Mesa to set GL state and
+ * performing normal triangle rendering.  The intent of this path is to
+ * have as generic a path as possible, so that any driver could make use of
+ * it.
+ */
+
+
+void radeon_clear_tris(GLcontext *ctx, GLbitfield mask)
+{
+   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+   GLfloat vertices[4][3];
+   GLfloat color[4][4];
+   GLfloat dst_z;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
+   int i;
+   GLboolean saved_fp_enable = GL_FALSE, saved_vp_enable = GL_FALSE;
+   GLboolean saved_shader_program = 0;
+   unsigned int saved_active_texture;
+
+   assert((mask & ~(TRI_CLEAR_COLOR_BITS | BUFFER_BIT_DEPTH |
+                   BUFFER_BIT_STENCIL)) == 0);   
+
+   _mesa_PushAttrib(GL_COLOR_BUFFER_BIT |
+                   GL_CURRENT_BIT |
+                   GL_DEPTH_BUFFER_BIT |
+                   GL_ENABLE_BIT |
+                   GL_POLYGON_BIT |
+                   GL_STENCIL_BUFFER_BIT |
+                   GL_TRANSFORM_BIT |
+                   GL_CURRENT_BIT);
+   _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+   saved_active_texture = ctx->Texture.CurrentUnit;
+  
+  /* Disable existing GL state we don't want to apply to a clear. */
+   _mesa_Disable(GL_ALPHA_TEST);
+   _mesa_Disable(GL_BLEND);
+   _mesa_Disable(GL_CULL_FACE);
+   _mesa_Disable(GL_FOG);
+   _mesa_Disable(GL_POLYGON_SMOOTH);
+   _mesa_Disable(GL_POLYGON_STIPPLE);
+   _mesa_Disable(GL_POLYGON_OFFSET_FILL);
+   _mesa_Disable(GL_LIGHTING);
+   _mesa_Disable(GL_CLIP_PLANE0);
+   _mesa_Disable(GL_CLIP_PLANE1);
+   _mesa_Disable(GL_CLIP_PLANE2);
+   _mesa_Disable(GL_CLIP_PLANE3);
+   _mesa_Disable(GL_CLIP_PLANE4);
+   _mesa_Disable(GL_CLIP_PLANE5);
+   _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+   if (ctx->Extensions.ARB_fragment_program && ctx->FragmentProgram.Enabled) {
+      saved_fp_enable = GL_TRUE;
+      _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB);
+   }
+   if (ctx->Extensions.ARB_vertex_program && ctx->VertexProgram.Enabled) {
+      saved_vp_enable = GL_TRUE;
+      _mesa_Disable(GL_VERTEX_PROGRAM_ARB);
+   }
+   if (ctx->Extensions.ARB_shader_objects && ctx->Shader.CurrentProgram) {
+      saved_shader_program = ctx->Shader.CurrentProgram->Name;
+      _mesa_UseProgramObjectARB(0);
+   }
+   
+   if (ctx->Texture._EnabledUnits != 0) {
+      int i;
+      
+      for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+        _mesa_ActiveTextureARB(GL_TEXTURE0 + i);
+        _mesa_Disable(GL_TEXTURE_1D);
+        _mesa_Disable(GL_TEXTURE_2D);
+        _mesa_Disable(GL_TEXTURE_3D);
+        if (ctx->Extensions.ARB_texture_cube_map)
+           _mesa_Disable(GL_TEXTURE_CUBE_MAP_ARB);
+        if (ctx->Extensions.NV_texture_rectangle)
+           _mesa_Disable(GL_TEXTURE_RECTANGLE_NV);
+        if (ctx->Extensions.MESA_texture_array) {
+           _mesa_Disable(GL_TEXTURE_1D_ARRAY_EXT);
+           _mesa_Disable(GL_TEXTURE_2D_ARRAY_EXT);
+        }
+      }
+   }
+  
+#if FEATURE_ARB_vertex_buffer_object
+   _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+   _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+#endif
+
+   radeon_meta_set_passthrough_transform(rmesa);
+   
+   for (i = 0; i < 4; i++) {
+      color[i][0] = ctx->Color.ClearColor[0];
+      color[i][1] = ctx->Color.ClearColor[1];
+      color[i][2] = ctx->Color.ClearColor[2];
+      color[i][3] = ctx->Color.ClearColor[3];
+   }
+
+   /* convert clear Z from [0,1] to NDC coord in [-1,1] */
+
+   dst_z = -1.0 + 2.0 * ctx->Depth.Clear;
+   /* Prepare the vertices, which are the same regardless of which buffer we're
+    * drawing to.
+    */
+   vertices[0][0] = fb->_Xmin;
+   vertices[0][1] = fb->_Ymin;
+   vertices[0][2] = dst_z;
+   vertices[1][0] = fb->_Xmax;
+   vertices[1][1] = fb->_Ymin;
+   vertices[1][2] = dst_z;
+   vertices[2][0] = fb->_Xmax;
+   vertices[2][1] = fb->_Ymax;
+   vertices[2][2] = dst_z;
+   vertices[3][0] = fb->_Xmin;
+   vertices[3][1] = fb->_Ymax;
+   vertices[3][2] = dst_z;
+
+   _mesa_ColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &color);
+   _mesa_VertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), &vertices);
+   _mesa_Enable(GL_COLOR_ARRAY);
+   _mesa_Enable(GL_VERTEX_ARRAY);
+
+   while (mask != 0) {
+      GLuint this_mask = 0;
+      GLuint color_bit;
+
+      color_bit = _mesa_ffs(mask & TRI_CLEAR_COLOR_BITS);
+      if (color_bit != 0)
+        this_mask |= (1 << (color_bit - 1));
+
+      /* Clear depth/stencil in the same pass as color. */
+      this_mask |= (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL));
+
+      /* Select the current color buffer and use the color write mask if
+       * we have one, otherwise don't write any color channels.
+       */
+      if (this_mask & BUFFER_BIT_FRONT_LEFT)
+        _mesa_DrawBuffer(GL_FRONT_LEFT);
+      else if (this_mask & BUFFER_BIT_BACK_LEFT)
+        _mesa_DrawBuffer(GL_BACK_LEFT);
+      else if (color_bit != 0)
+        _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0 +
+                         (color_bit - BUFFER_COLOR0 - 1));
+      else
+        _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+      /* Control writing of the depth clear value to depth. */
+      if (this_mask & BUFFER_BIT_DEPTH) {
+        _mesa_DepthFunc(GL_ALWAYS);
+        _mesa_DepthMask(GL_TRUE);
+        _mesa_Enable(GL_DEPTH_TEST);
+      } else {
+        _mesa_Disable(GL_DEPTH_TEST);
+        _mesa_DepthMask(GL_FALSE);
+      }
+
+      /* Control writing of the stencil clear value to stencil. */
+      if (this_mask & BUFFER_BIT_STENCIL) {
+        _mesa_Enable(GL_STENCIL_TEST);
+        _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+        _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, ctx->Stencil.Clear,
+                                  ctx->Stencil.WriteMask[0]);
+      } else {
+        _mesa_Disable(GL_STENCIL_TEST);
+      }
+
+      CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4));
+
+      mask &= ~this_mask;
+   }
+
+   radeon_meta_restore_transform(rmesa);
+
+   _mesa_ActiveTextureARB(GL_TEXTURE0 + saved_active_texture);
+   if (saved_fp_enable)
+      _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB);
+   if (saved_vp_enable)
+      _mesa_Enable(GL_VERTEX_PROGRAM_ARB);
+
+   if (saved_shader_program)
+      _mesa_UseProgramObjectARB(saved_shader_program);
+
+   _mesa_PopClientAttrib();
+   _mesa_PopAttrib();
+}