Add accelerated CopyPixels for non-overlapping, 1:1 blits.
authorEric Anholt <anholt@FreeBSD.org>
Wed, 29 Nov 2006 01:16:12 +0000 (01:16 +0000)
committerEric Anholt <anholt@FreeBSD.org>
Wed, 29 Nov 2006 01:16:12 +0000 (01:16 +0000)
Submitted by Gary Wong <gtw@gnu.org>

src/mesa/drivers/dri/i965/brw_context.c
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_metaops.c
src/mesa/drivers/dri/i965/brw_tex.c
src/mesa/drivers/dri/i965/brw_vtbl.c
src/mesa/drivers/dri/i965/brw_wm_surface_state.c
src/mesa/drivers/dri/i965/intel_buffers.c
src/mesa/drivers/dri/i965/intel_context.h
src/mesa/drivers/dri/i965/intel_pixel_copy.c
src/mesa/drivers/dri/i965/intel_tex_validate.c

index c1f6617f3fd3a594ee8a1664ff05aec9ecde3bd8..bc422c1a50bef20d274ffe7f240893ff68fa3636 100644 (file)
@@ -156,6 +156,8 @@ GLboolean brwCreateContext( const __GLcontextModes *mesaVis,
 
    brw_ProgramCacheInit( ctx );
 
+   brw_FrameBufferTexInit( brw );
+
    /* Hook our functions into exec and compile dispatch tables.  Only
     * fallback on out-of-memory situations.
     */
index 1137bfd2c76e82d61a4a846b9f0db2622d9b4d6c..a57c794834f1d2349117925ef262280cf518133b 100644 (file)
@@ -485,7 +485,7 @@ struct brw_context
        */
       struct brw_state_pointers attribs;
       struct gl_vertex_program *vp;
-      struct gl_fragment_program *fp;
+      struct gl_fragment_program *fp, *fp_tex;
 
       struct gl_buffer_object *vbo;
 
@@ -493,6 +493,8 @@ struct brw_context
       struct intel_region *saved_depth_region;
 
       GLuint restore_draw_mask;
+      struct gl_fragment_program *restore_fp;
+      
       GLboolean active;
    } metaops;
 
@@ -672,6 +674,8 @@ void brw_destroy_state( struct brw_context *brw );
  */
 void brwUpdateTextureState( struct intel_context *intel );
 void brwInitTextureFuncs( struct dd_function_table *functions );
+void brw_FrameBufferTexInit( struct brw_context *brw );
+void brw_FrameBufferTexDestroy( struct brw_context *brw );
 
 /*======================================================================
  * brw_metaops.c
index 18ca7b1341254f6c97252d149b16f0234cb6c882..ca8e1d30805e578a3dff62903634c4e4a9f9c5f3 100644 (file)
@@ -27,6 +27,7 @@
  /*
   * Authors:
   *   Keith Whitwell <keith@tungstengraphics.com>
+  *   frame buffer texture by Gary Wong <gtw@gnu.org>
   */
  
 
@@ -94,22 +95,26 @@ static void init_attribs( struct brw_context *brw )
    DUP(brw, gl_fragment_program_state, FragmentProgram);
 }
 
-static void install_attribs( struct brw_context *brw )
+static void install_vertex_attribs( struct brw_context *brw )
 {
-   INSTALL(brw, Color, _NEW_COLOR);
-   INSTALL(brw, Depth, _NEW_DEPTH);
-   INSTALL(brw, Fog, _NEW_FOG);
    INSTALL(brw, Hint, _NEW_HINT);
    INSTALL(brw, Light, _NEW_LIGHT);
    INSTALL(brw, Line, _NEW_LINE);
    INSTALL(brw, Point, _NEW_POINT);
    INSTALL(brw, Polygon, _NEW_POLYGON);
-   INSTALL(brw, Scissor, _NEW_SCISSOR);
-   INSTALL(brw, Stencil, _NEW_STENCIL);
-   INSTALL(brw, Texture, _NEW_TEXTURE);
    INSTALL(brw, Transform, _NEW_TRANSFORM);
    INSTALL(brw, Viewport, _NEW_VIEWPORT);
    INSTALL(brw, VertexProgram, _NEW_PROGRAM);
+}
+
+static void install_fragment_attribs( struct brw_context *brw )
+{
+   INSTALL(brw, Color, _NEW_COLOR);
+   INSTALL(brw, Depth, _NEW_DEPTH);
+   INSTALL(brw, Fog, _NEW_FOG);
+   INSTALL(brw, Scissor, _NEW_SCISSOR);
+   INSTALL(brw, Stencil, _NEW_STENCIL);
+   INSTALL(brw, Texture, _NEW_TEXTURE);
    INSTALL(brw, FragmentProgram, _NEW_PROGRAM);
 }
 
@@ -144,6 +149,15 @@ static const char *fp_prog =
       "MOV result.color, fragment.color;\n"
       "END\n";
 
+static const char *fp_tex_prog =
+      "!!ARBfp1.0\n"
+      "TEMP a;\n"
+      "ADD a, fragment.position, program.local[0];\n"
+      "MUL a, a, program.local[1];\n"
+      "TEX result.color, a, texture[0], 2D;\n"
+      "MOV result.depth.z, fragment.position;\n"
+      "END\n";
+
 /* Derived values of importance:
  *
  *   FragmentProgram->_Current
@@ -170,6 +184,9 @@ static void init_metaops_state( struct brw_context *brw )
    brw->metaops.fp = (struct gl_fragment_program *)
       ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 1 );
 
+   brw->metaops.fp_tex = (struct gl_fragment_program *)
+      ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 1 );
+
    brw->metaops.vp = (struct gl_vertex_program *)
       ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 1 );
 
@@ -177,6 +194,10 @@ static void init_metaops_state( struct brw_context *brw )
                                    fp_prog, strlen(fp_prog),
                                    brw->metaops.fp);
 
+   _mesa_parse_arb_fragment_program(ctx, GL_FRAGMENT_PROGRAM_ARB, 
+                                   fp_tex_prog, strlen(fp_tex_prog),
+                                   brw->metaops.fp_tex);
+
    _mesa_parse_arb_vertex_program(ctx, GL_VERTEX_PROGRAM_ARB, 
                                  vp_prog, strlen(vp_prog),
                                  brw->metaops.vp);
@@ -267,7 +288,56 @@ static void meta_color_mask( struct intel_context *intel, GLboolean state )
 
 static void meta_no_texture( struct intel_context *intel )
 {
-   /* Nothing to do */
+   struct brw_context *brw = brw_context(&intel->ctx);
+   
+   brw->metaops.attribs.FragmentProgram->_Current = brw->metaops.fp;
+   
+   brw->metaops.attribs.Texture->CurrentUnit = 0;
+   brw->metaops.attribs.Texture->_EnabledUnits = 0;
+   brw->metaops.attribs.Texture->_EnabledCoordUnits = 0;
+   brw->metaops.attribs.Texture->Unit[ 0 ].Enabled = 0;
+   brw->metaops.attribs.Texture->Unit[ 0 ]._ReallyEnabled = 0;
+
+   brw->state.dirty.mesa |= _NEW_TEXTURE | _NEW_PROGRAM;
+}
+
+static void meta_frame_buffer_texture( struct intel_context *intel,
+                                      GLint xoff, GLint yoff )
+{
+   struct brw_context *brw = brw_context(&intel->ctx);
+   struct intel_region *region = intel_drawbuf_region( intel );
+   
+   INSTALL(brw, FragmentProgram, _NEW_PROGRAM);
+
+   brw->metaops.attribs.FragmentProgram->_Current = brw->metaops.fp_tex;
+   /* This is unfortunate, but seems to be necessary, since later on we
+      will end up calling _mesa_load_state_parameters to lookup the
+      local params (below), and that will want to look in ctx.FragmentProgram
+      instead of brw->attribs.FragmentProgram. */
+   intel->ctx.FragmentProgram.Current = brw->metaops.fp_tex;
+
+   brw->metaops.fp_tex->Base.LocalParams[ 0 ][ 0 ] = xoff;
+   brw->metaops.fp_tex->Base.LocalParams[ 0 ][ 1 ] = yoff;
+   brw->metaops.fp_tex->Base.LocalParams[ 0 ][ 2 ] = 0.0;
+   brw->metaops.fp_tex->Base.LocalParams[ 0 ][ 3 ] = 0.0;
+   brw->metaops.fp_tex->Base.LocalParams[ 1 ][ 0 ] =
+      1.0 / region->pitch;
+   brw->metaops.fp_tex->Base.LocalParams[ 1 ][ 1 ] =
+      -1.0 / region->height;
+   brw->metaops.fp_tex->Base.LocalParams[ 1 ][ 2 ] = 0.0;
+   brw->metaops.fp_tex->Base.LocalParams[ 1 ][ 3 ] = 1.0;
+   
+   brw->metaops.attribs.Texture->CurrentUnit = 0;
+   brw->metaops.attribs.Texture->_EnabledUnits = 1;
+   brw->metaops.attribs.Texture->_EnabledCoordUnits = 1;
+   brw->metaops.attribs.Texture->Unit[ 0 ].Enabled = TEXTURE_2D_BIT;
+   brw->metaops.attribs.Texture->Unit[ 0 ]._ReallyEnabled = TEXTURE_2D_BIT;
+   brw->metaops.attribs.Texture->Unit[ 0 ].Current2D =
+      intel->frame_buffer_texobj;
+   brw->metaops.attribs.Texture->Unit[ 0 ]._Current =
+      intel->frame_buffer_texobj;
+
+   brw->state.dirty.mesa |= _NEW_TEXTURE | _NEW_PROGRAM;
 }
 
 
@@ -406,7 +476,8 @@ static void meta_draw_quad(struct intel_context *intel,
 }
 
 
-static void install_meta_state( struct intel_context *intel )
+static void install_meta_state( struct intel_context *intel,
+                               GLenum state )
 {
    GLcontext *ctx = &intel->ctx;
    struct brw_context *brw = brw_context(ctx);
@@ -415,10 +486,14 @@ static void install_meta_state( struct intel_context *intel )
       init_metaops_state(brw);
    }
 
-   install_attribs(brw);
+   install_vertex_attribs(brw);
+   if( state == META_FULL )
+      install_fragment_attribs(brw);
+   
    meta_no_texture(&brw->intel);
    meta_flat_shade(&brw->intel);
    brw->metaops.restore_draw_mask = ctx->DrawBuffer->_ColorDrawBufferMask[0];
+   brw->metaops.restore_fp = ctx->FragmentProgram.Current;
 
    /* This works without adjusting refcounts.  Fix later? 
     */
@@ -437,6 +512,7 @@ static void leave_meta_state( struct intel_context *intel )
    restore_attribs(brw);
 
    ctx->DrawBuffer->_ColorDrawBufferMask[0] = brw->metaops.restore_draw_mask;
+   ctx->FragmentProgram.Current = brw->metaops.restore_fp;
 
    brw->state.draw_region = brw->metaops.saved_draw_region;
    brw->state.depth_region = brw->metaops.saved_depth_region;
@@ -463,6 +539,7 @@ void brw_init_metaops( struct brw_context *brw )
    brw->intel.vtbl.meta_depth_replace = meta_depth_replace;
    brw->intel.vtbl.meta_color_mask = meta_color_mask;
    brw->intel.vtbl.meta_no_texture = meta_no_texture;
+   brw->intel.vtbl.meta_frame_buffer_texture = meta_frame_buffer_texture;
    brw->intel.vtbl.meta_draw_region = meta_draw_region;
    brw->intel.vtbl.meta_draw_quad = meta_draw_quad;
 
@@ -479,5 +556,6 @@ void brw_destroy_metaops( struct brw_context *brw )
       ctx->Driver.DeleteBuffer( ctx, brw->metaops.vbo );
 
 /*    ctx->Driver.DeleteProgram( ctx, brw->metaops.fp ); */
+/*    ctx->Driver.DeleteProgram( ctx, brw->metaops.fp_tex ); */
 /*    ctx->Driver.DeleteProgram( ctx, brw->metaops.vp ); */
 }
index 8332d869e1d3a05a49c3cd8db6d319fcc6d210f8..c3ffa9e65777b9a46e75d8a7d38f99d7a69aceea 100644 (file)
 #include "simple_list.h"
 #include "enums.h"
 #include "image.h"
+#include "teximage.h"
 #include "texstore.h"
 #include "texformat.h"
 #include "texmem.h"
 
+#include "intel_context.h"
 #include "intel_ioctl.h"
+#include "intel_regions.h"
 #include "brw_context.h"
 #include "brw_defines.h"
 
@@ -179,3 +182,32 @@ void brwInitTextureFuncs( struct dd_function_table *functions )
 {
    functions->ChooseTextureFormat = brwChooseTextureFormat;
 }
+
+void brw_FrameBufferTexInit( struct brw_context *brw )
+{
+   struct intel_context *intel = &brw->intel;
+   GLcontext *ctx = &intel->ctx;
+   struct intel_region *region = intel->front_region;
+   struct gl_texture_object *obj;
+   struct gl_texture_image *img;
+   
+   intel->frame_buffer_texobj = obj =
+      ctx->Driver.NewTextureObject( ctx, (GLuint) -1, GL_TEXTURE_2D );
+
+   obj->MinFilter = GL_NEAREST;
+   obj->MagFilter = GL_NEAREST;
+
+   img = ctx->Driver.NewTextureImage( ctx );
+
+   _mesa_init_teximage_fields( ctx, GL_TEXTURE_2D, img,
+                              region->pitch, region->height, 1, 0,
+                              region->cpp == 4 ? GL_RGBA : GL_RGB );
+   
+   _mesa_set_tex_image( obj, GL_TEXTURE_2D, 0, img );
+}
+
+void brw_FrameBufferTexDestroy( struct brw_context *brw )
+{
+   brw->intel.ctx.Driver.DeleteTexture( &brw->intel.ctx,
+                                       brw->intel.frame_buffer_texobj );
+}
index 4896882034b43869fafd90b1203c7e9b3d6cc4a3..ac09754e3ae537b70b7d70b886b346ab18634522 100644 (file)
@@ -72,6 +72,7 @@ static void brw_destroy_context( struct intel_context *intel )
    brw_save_destroy( ctx );
 
    brw_ProgramCacheDestroy( ctx );
+   brw_FrameBufferTexDestroy( brw );
 }
 
 /* called from intelDrawBuffer()
index 5c7dc500cab29f28f232eb922bb438d243ef4a73..d24c618a668b6ba950f10ae8175e414c37938b6b 100644 (file)
@@ -239,6 +239,12 @@ static void upload_wm_surfaces(struct brw_context *brw )
         brw->wm.bind.surf_ss_offset[i+1] = brw_cache_data( &brw->cache[BRW_SS_SURFACE], &surf );
         brw->wm.nr_surfaces = i+2;
       }
+      else if( texUnit->_ReallyEnabled &&
+              texUnit->_Current == intel->frame_buffer_texobj )
+      {
+        brw->wm.bind.surf_ss_offset[i+1] = brw->wm.bind.surf_ss_offset[0];
+        brw->wm.nr_surfaces = i+2;
+      }    
       else {
         brw->wm.bind.surf_ss_offset[i+1] = 0;
       }
index d155c039d77872017e943b20df8ce262e5ed0249..645ac8e4f927c044bf8ba0ab1a994db22e4574ec 100644 (file)
@@ -235,7 +235,7 @@ static void intelClearWithTris(struct intel_context *intel,
 
    {
 
-      intel->vtbl.install_meta_state(intel);
+      intel->vtbl.install_meta_state(intel, META_FULL);
 
       /* Get clear bounds after locking */
       cx = ctx->DrawBuffer->_Xmin;
index 2df8faef28eaa4044c279ddd73cad8f868d31eb8..a8f7a61ba3bdf459b21ce584380e3628d9aaaccc 100644 (file)
@@ -86,6 +86,11 @@ struct intel_texture_object
 
 
 
+/* Identifiers for use with install_meta_state below */
+enum
+{
+   META_FULL, META_VERTEX_ONLY
+};
 
 struct intel_context
 {
@@ -132,7 +137,8 @@ struct intel_context
 
       /* Metaops: 
        */
-      void (*install_meta_state)( struct intel_context *intel );
+      void (*install_meta_state)( struct intel_context *intel,
+                                 GLenum state );
       void (*leave_meta_state)( struct intel_context *intel );
 
       void (*meta_draw_region)( struct intel_context *intel,
@@ -151,6 +157,8 @@ struct intel_context
       void (*meta_no_stencil_write)( struct intel_context *intel );
       void (*meta_no_depth_write)( struct intel_context *intel );
       void (*meta_no_texture)( struct intel_context *intel );
+      void (*meta_frame_buffer_texture)( struct intel_context *intel,
+                                        GLint xoff, GLint yoff );
 
       void (*meta_draw_quad)(struct intel_context *intel, 
                             GLfloat x0, GLfloat x1,
@@ -218,6 +226,7 @@ struct intel_context
    int drawY;
    GLuint numClipRects;                /* cliprects for that buffer */
    drm_clip_rect_t *pClipRects;
+   struct gl_texture_object *frame_buffer_texobj;
 
    GLboolean scissor;
    drm_clip_rect_t draw_rect;
index 55b58a8f6702b1dc02b74e5e584684415718e7a5..0279311976e1b930f4a6c7f0f16c549063e1e460 100644 (file)
@@ -80,8 +80,6 @@ intel_check_blit_fragment_ops(GLcontext * ctx)
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   /* Could do logicop with the blitter: 
-    */
    return !(ctx->_ImageTransferState ||
            ctx->RenderMode != GL_RENDER ||
             ctx->Color.AlphaEnabled ||
@@ -223,6 +221,65 @@ do_blit_copypixels(GLcontext * ctx,
    return GL_TRUE;
 }
 
+/**
+ * CopyPixels with metaops.  We can support (most) fragment options that way.
+ */
+static GLboolean
+do_meta_copypixels(GLcontext * ctx,
+                   GLint srcx, GLint srcy,
+                   GLsizei width, GLsizei height,
+                   GLint dstx, GLint dsty, GLenum type)
+{
+   struct intel_context *intel = intel_context(ctx);
+
+   /* We're going to cheat and use texturing to get the source region
+    * duplicated.  Trying to cope with the case where texturing is
+    * already applied to fragments would be messy (and it's an unusual
+    * thing to want anyway), so we leave that to swrast.
+    *
+    * We don't want to worry about any case other than GL_COLOR, either
+    * (though we could, with a bit more work).
+    *
+    * PixelMap, PixelTransfer, PixelZoom etc. could also be handled with
+    * a bit more intelligence in metaops.
+    */
+   if( ctx->_ImageTransferState ||
+       ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F ||
+       ctx->RenderMode != GL_RENDER ||
+       ctx->Texture._EnabledUnits ||
+       ctx->FragmentProgram._Enabled ||
+       type != GL_COLOR )
+      return GL_FALSE;
+
+   /* We don't yet handle copying between two different buffers (which
+    * would really only require filling out a new surface state for
+    * the source instead of aliasing the draw one).  Nor do we handle
+    * overlapping source/dest rectangles (since I assume there is no
+    * way to force the hardware to guarantee the drawing order that
+    * the GL specifies -- if so, the fastest approach might be to use
+    * the blitter to copy the source to a temporary surface and then
+    * map that back onto the destination).  Of course, overlapping
+    * areas in different buffers would be fine.
+    */
+   if( ctx->Color.DrawBuffer[0] != ctx->ReadBuffer->ColorReadBuffer ||
+       ( abs( srcx - dstx ) < width && abs( srcy - dsty ) < height ) )
+      return GL_FALSE;
+   
+   intel->vtbl.install_meta_state( intel, META_VERTEX_ONLY );
+
+   intel->vtbl.meta_frame_buffer_texture( intel, srcx - dstx, srcy - dsty );
+   
+   intel->vtbl.meta_draw_quad( intel,
+                              dstx, dstx + width,
+                              dsty, dsty + height,
+                              ctx->Current.RasterPos[ 2 ],
+                              0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0 );
+   
+   intel->vtbl.leave_meta_state( intel );
+   
+   return GL_TRUE;
+}
+   
 void
 intelCopyPixels(GLcontext * ctx,
                 GLint srcx, GLint srcy,
@@ -235,6 +292,12 @@ intelCopyPixels(GLcontext * ctx,
    if (do_blit_copypixels(ctx, srcx, srcy, width, height, destx, desty, type))
       return;
 
+   if (INTEL_DEBUG & DEBUG_PIXEL)
+      _mesa_printf("fallback to do_meta_copypixels\n");
+   
+   if (do_meta_copypixels(ctx, srcx, srcy, width, height, destx, desty, type))
+      return;
+   
    if (INTEL_DEBUG & DEBUG_PIXEL)
       _mesa_printf("fallback to _swrast_CopyPixels\n");
 
index 91ae0970a04f1d43c67b4ed9eff3a35af93196fa..cb23b9dd87922a4b0752205f98dc59960b0c8575 100644 (file)
@@ -133,6 +133,9 @@ GLuint intel_finalize_mipmap_tree( struct intel_context *intel,
    GLuint nr_faces = 0;
    struct gl_texture_image *firstImage;
 
+   if( tObj == intel->frame_buffer_texobj )
+      return GL_FALSE;
+   
    /* We know/require this is true by now: 
     */
    assert(intelObj->base.Complete);