Mesa (radeon-rewrite): radeon: implement userspace clears

Dave Airlie airlied at kemper.freedesktop.org
Fri Mar 6 06:06:46 UTC 2009


Module: Mesa
Branch: radeon-rewrite
Commit: c6ac53bc40508ab2f0b9e023eee7ec3793fdf917
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=c6ac53bc40508ab2f0b9e023eee7ec3793fdf917

Author: Dave Airlie <airlied at redhat.com>
Date:   Fri Mar  6 16:05:22 2009 +1000

radeon: implement userspace clears

This is pretty much Eric Anholts implementation of clear using the GL state machine
from the Intel drivers.

It works quite well for now for us, probably could do with trying to use Z engine for
clears.

---

 src/mesa/drivers/dri/radeon/radeon_context.h |   15 ++
 src/mesa/drivers/dri/radeon/radeon_ioctl.c   |  252 +++++++++++++++++++++++---
 2 files changed, 238 insertions(+), 29 deletions(-)

diff --git a/src/mesa/drivers/dri/radeon/radeon_context.h b/src/mesa/drivers/dri/radeon/radeon_context.h
index 2efabd1..2015e96 100644
--- a/src/mesa/drivers/dri/radeon/radeon_context.h
+++ b/src/mesa/drivers/dri/radeon/radeon_context.h
@@ -435,8 +435,23 @@ struct r100_context {
 	GLuint c_textureBytes;
 	GLuint c_vertexBuffers;
 
+  struct {
+      struct gl_fragment_program *bitmap_fp;
+      struct gl_vertex_program *passthrough_vp;
+
+      struct gl_fragment_program *saved_fp;
+      GLboolean saved_fp_enable;
+      struct gl_vertex_program *saved_vp;
+      GLboolean saved_vp_enable;
+
+      GLint saved_vp_x, saved_vp_y;
+      GLsizei saved_vp_width, saved_vp_height;
+      GLenum saved_matrix_mode;
+   } meta;
+
 };
 
+
 #define R100_CONTEXT(ctx)		((r100ContextPtr)(ctx->DriverCtx))
 
 
diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.c b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
index 6a24fc4..22584f4 100644
--- a/src/mesa/drivers/dri/radeon/radeon_ioctl.c
+++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
@@ -37,6 +37,20 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <sched.h>
 #include <errno.h> 
 
+#include "main/attrib.h"
+#include "main/enable.h"
+#include "main/blend.h"
+#include "main/bufferobj.h"
+#include "main/buffers.h"
+#include "main/depth.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/glheader.h"
 #include "main/imports.h"
 #include "main/simple_list.h"
@@ -405,42 +419,221 @@ void radeonEmitAOS( r100ContextPtr rmesa,
  */
 #define RADEON_MAX_CLEARS	256
 
-static void radeonUserClear(GLcontext *ctx, GLuint flags)
+
+
+static void
+r100_meta_set_passthrough_transform(r100ContextPtr r100)
 {
-  GLuint mask = 0;
+   GLcontext *ctx = r100->radeon.glCtx;
 
-  if (flags & RADEON_FRONT)
-    mask |= BUFFER_BIT_FRONT_LEFT;
+   r100->meta.saved_vp_x = ctx->Viewport.X;
+   r100->meta.saved_vp_y = ctx->Viewport.Y;
+   r100->meta.saved_vp_width = ctx->Viewport.Width;
+   r100->meta.saved_vp_height = ctx->Viewport.Height;
+   r100->meta.saved_matrix_mode = ctx->Transform.MatrixMode;
 
-  if (flags & RADEON_BACK)
-    mask |= BUFFER_BIT_BACK_LEFT;
+   _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
 
-  if (flags & RADEON_DEPTH)
-    mask |= BUFFER_BIT_DEPTH;
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+   _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1);
 
-  if (flags & RADEON_STENCIL)
-    mask |= BUFFER_BIT_STENCIL;
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+}
 
-#if 1
-  _swrast_Clear(ctx, mask);
-#else
-   for ( i = 0 ; i < dPriv->numClipRects ; ) {
+static void
+r100_meta_restore_transform(r100ContextPtr r100)
+{
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PopMatrix();
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PopMatrix();
 
-   }
+   _mesa_MatrixMode(r100->meta.saved_matrix_mode);
 
-   if (flags & (RADEON_FRONT | RADEON_BACK)) {
-     	OUT_BATCH(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
-	OUT_BATCH((RADEON_WAIT_3D_IDLECLEAN |
-		  RADEON_WAIT_HOST_IDLECLEAN));
-	OUT_BATCH_REGVAL(RADEON_DP_WRITE_MASK, 0); //clear->color_mask);
+   _mesa_Viewport(r100->meta.saved_vp_x, r100->meta.saved_vp_y,
+		  r100->meta.saved_vp_width, r100->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.
+ */
+static void radeon_clear_tris(GLcontext *ctx, GLbitfield mask)
+{
+   r100ContextPtr rmesa = R100_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 & ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_FRONT_LEFT |
+		    BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) == 0);
+
+   _mesa_PushAttrib(GL_COLOR_BUFFER_BIT |
+		    GL_CURRENT_BIT |
+		    GL_DEPTH_BUFFER_BIT |
+		    GL_ENABLE_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);
+   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 ((flags & (RADEON_DEPTH | RADEON_STENCIL))
-       && (flags & RADEON_CLEAR_FASTZ)) {
+  
+   r100_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;
+
+      if (mask & BUFFER_BIT_BACK_LEFT)
+	 this_mask = BUFFER_BIT_BACK_LEFT;
+      else if (mask & BUFFER_BIT_FRONT_LEFT)
+	 this_mask = BUFFER_BIT_FRONT_LEFT;
+
+      /* 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
+	 _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_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, 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;
    }
-#endif
+
+   r100_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();
+}
+
+static void radeonUserClear(GLcontext *ctx, GLuint mask)
+{
+   radeon_clear_tris(ctx, mask);
 }
 
 static void radeonKernelClear(GLcontext *ctx, GLuint flags)
@@ -570,6 +763,7 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
    __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
    GLuint flags = 0;
    GLuint color_mask = 0;
+   GLuint orig_mask = mask;
 
    if ( RADEON_DEBUG & DEBUG_IOCTL ) {
       fprintf( stderr, "radeonClear\n");
@@ -582,7 +776,7 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
 	 return;
    }
    
-   radeonFlush( ctx ); 
+   radeon_firevertices(&rmesa->radeon); 
 
    if ( mask & BUFFER_BIT_FRONT_LEFT ) {
       flags |= RADEON_FRONT;
@@ -627,11 +821,11 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
    }
 
    if (rmesa->radeon.radeonScreen->kernel_mm)
-      radeonUserClear(ctx, flags);
-   else
+     radeonUserClear(ctx, orig_mask);
+   else {
       radeonKernelClear(ctx, flags);
-
-   rmesa->radeon.hw.all_dirty = GL_TRUE;
+      rmesa->radeon.hw.all_dirty = GL_TRUE;
+   }
 }
 
 void radeonInitIoctlFuncs( GLcontext *ctx )




More information about the mesa-commit mailing list