From a73ae3d5eb8419feab5aea26573aa41b72f941eb Mon Sep 17 00:00:00 2001
From: Keith Whitwell <keith@tungstengraphics.com>
Date: Fri, 2 May 2008 16:46:31 +0100
Subject: gallium: Add texture usage flags, special-case allocation of display
 targets

For many envirionments it's necessary to allocate display targets
in a window-system friendly manner.  Add facilities so that a driver
can tell if a texture is likely to be used to generate a display surface
and if use special allocation paths if necessary.

Hook up softpipe to call into the winsys->surface_alloc_storage()
routine in this case, though we probably want to change that interface
slightly also.
---
 src/gallium/drivers/softpipe/sp_texture.c      | 101 ++++++++++++++++---------
 src/gallium/drivers/softpipe/sp_texture.h      |   2 +-
 src/gallium/include/pipe/p_state.h             |   6 +-
 src/mesa/state_tracker/st_atom_pixeltransfer.c |   3 +-
 src/mesa/state_tracker/st_cb_bitmap.c          |   6 +-
 src/mesa/state_tracker/st_cb_drawpixels.c      |   6 +-
 src/mesa/state_tracker/st_cb_fbo.c             |  23 ++++--
 src/mesa/state_tracker/st_cb_texture.c         |  10 ++-
 src/mesa/state_tracker/st_texture.c            |   4 +-
 src/mesa/state_tracker/st_texture.h            |   3 +-
 10 files changed, 111 insertions(+), 53 deletions(-)

(limited to 'src')

diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c
index 2b31cd4f25..599ff2ac45 100644
--- a/src/gallium/drivers/softpipe/sp_texture.c
+++ b/src/gallium/drivers/softpipe/sp_texture.c
@@ -52,40 +52,87 @@ static unsigned minify( unsigned d )
 }
 
 
-static void
-softpipe_texture_layout(struct softpipe_texture * spt)
+/* Conventional allocation path for non-display textures:
+ */
+static boolean
+softpipe_texture_layout(struct pipe_screen *screen,
+                        struct softpipe_texture * spt)
 {
+   struct pipe_winsys *ws = screen->winsys;
    struct pipe_texture *pt = &spt->base;
    unsigned level;
    unsigned width = pt->width[0];
    unsigned height = pt->height[0];
    unsigned depth = pt->depth[0];
 
-   spt->buffer_size = 0;
+   unsigned buffer_size = 0;
 
    for (level = 0; level <= pt->last_level; level++) {
       pt->width[level] = width;
       pt->height[level] = height;
       pt->depth[level] = depth;
+      spt->pitch[level] = width;
 
-      spt->level_offset[level] = spt->buffer_size;
+      spt->level_offset[level] = buffer_size;
 
-      spt->buffer_size += ((pt->compressed) ? MAX2(1, height/4) : height) *
-			  ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
-			  width * pt->cpp;
+      buffer_size += (((pt->compressed) ? MAX2(1, height/4) : height) *
+                      ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
+                      width * pt->cpp);
 
       width  = minify(width);
       height = minify(height);
       depth = minify(depth);
    }
+
+   spt->buffer = ws->buffer_create(ws, 32,
+                                   PIPE_BUFFER_USAGE_PIXEL,
+                                   buffer_size);
+
+   return spt->buffer != NULL;
 }
 
 
+
+/* Hack it up to use the old winsys->surface_alloc_storage()
+ * method for now:
+ */
+static boolean
+softpipe_displaytarget_layout(struct pipe_screen *screen,
+                              struct softpipe_texture * spt)
+{
+   struct pipe_winsys *ws = screen->winsys;
+   struct pipe_surface surf;
+   unsigned flags = (PIPE_BUFFER_USAGE_CPU_READ |
+                     PIPE_BUFFER_USAGE_CPU_WRITE |
+                     PIPE_BUFFER_USAGE_GPU_READ |
+                     PIPE_BUFFER_USAGE_GPU_WRITE);
+
+
+   memset(&surf, 0, sizeof(surf));
+
+   ws->surface_alloc_storage( ws, 
+                              &surf,
+                              spt->base.width[0], 
+                              spt->base.height[0],
+                              spt->base.format,
+                              flags);
+      
+   /* Now extract the goodies: 
+    */
+   spt->buffer = surf.buffer;
+   spt->pitch[0] = surf.pitch;
+
+   return spt->buffer != NULL;
+}
+
+
+
+
+
 static struct pipe_texture *
 softpipe_texture_create(struct pipe_screen *screen,
                         const struct pipe_texture *templat)
 {
-   struct pipe_winsys *ws = screen->winsys;
    struct softpipe_texture *spt = CALLOC_STRUCT(softpipe_texture);
    if (!spt)
       return NULL;
@@ -94,19 +141,21 @@ softpipe_texture_create(struct pipe_screen *screen,
    spt->base.refcount = 1;
    spt->base.screen = screen;
 
-   softpipe_texture_layout(spt);
-
-   spt->buffer = ws->buffer_create(ws, 32,
-                                   PIPE_BUFFER_USAGE_PIXEL,
-                                   spt->buffer_size);
-   if (!spt->buffer) {
-      FREE(spt);
-      return NULL;
+   if (spt->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET) {
+      if (!softpipe_displaytarget_layout(screen, spt))
+         goto fail;
    }
-
+   else {
+      if (!softpipe_texture_layout(screen, spt))
+         goto fail;
+   }
+    
    assert(spt->base.refcount == 1);
-
    return &spt->base;
+
+ fail:
+   FREE(spt);
+   return NULL;
 }
 
 
@@ -178,22 +227,6 @@ softpipe_get_tex_surface(struct pipe_screen *screen,
 	 assert(face == 0);
 	 assert(zslice == 0);
       }
-
-      if (usage & (PIPE_BUFFER_USAGE_CPU_WRITE |
-                   PIPE_BUFFER_USAGE_GPU_WRITE)) {
-         /* XXX if writing to the texture, invalidate the texcache entries!!! 
-          *
-          * Actually, no.  Flushing dependent contexts is still done
-          * explicitly and separately.  Hardware drivers won't insert
-          * FLUSH commands into a command stream at this point,
-          * neither should softpipe try to flush caches.  
-          *
-          * Those contexts could be living in separate threads & doing
-          * all sorts of unrelated stuff...  Context<->texture
-          * dependency tracking needs to happen elsewhere.
-          */
-         /* assert(0); */
-      }
    }
    return ps;
 }
diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h
index 2ba093320d..779a9d8fc9 100644
--- a/src/gallium/drivers/softpipe/sp_texture.h
+++ b/src/gallium/drivers/softpipe/sp_texture.h
@@ -42,11 +42,11 @@ struct softpipe_texture
    struct pipe_texture base;
 
    unsigned long level_offset[PIPE_MAX_TEXTURE_LEVELS];
+   unsigned long pitch[PIPE_MAX_TEXTURE_LEVELS];
 
    /* The data is held here:
     */
    struct pipe_buffer *buffer;
-   unsigned long buffer_size;
 };
 
 
diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
index 277ee4b319..d7565dff96 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -284,6 +284,10 @@ struct pipe_surface
 };
 
 
+#define PIPE_TEXTURE_USAGE_RENDER_TARGET   0x1
+#define PIPE_TEXTURE_USAGE_DISPLAY_TARGET  0x2 /* ie a backbuffer */
+#define PIPE_TEXTURE_USAGE_SAMPLER         0x4
+
 /**
  * Texture object.
  */
@@ -300,7 +304,7 @@ struct pipe_texture
    unsigned last_level:8;    /**< Index of last mipmap level present/defined */
    unsigned compressed:1;
    
-   unsigned usage;
+   unsigned tex_usage;          /* PIPE_TEXTURE_USAGE_* */
 
    /* These are also refcounted:
     */
diff --git a/src/mesa/state_tracker/st_atom_pixeltransfer.c b/src/mesa/state_tracker/st_atom_pixeltransfer.c
index 0c32d53c4a..e500ac8684 100644
--- a/src/mesa/state_tracker/st_atom_pixeltransfer.c
+++ b/src/mesa/state_tracker/st_atom_pixeltransfer.c
@@ -126,7 +126,8 @@ create_color_map_texture(GLcontext *ctx)
 
    /* create texture for color map/table */
    pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0,
-                          texSize, texSize, 1, 0);
+                          texSize, texSize, 1, 0,
+                          PIPE_TEXTURE_USAGE_SAMPLER);
    return pt;
 }
 
diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c
index 873b765c2c..f816e59104 100644
--- a/src/mesa/state_tracker/st_cb_bitmap.c
+++ b/src/mesa/state_tracker/st_cb_bitmap.c
@@ -321,7 +321,8 @@ make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height,
     * Create texture to hold bitmap pattern.
     */
    pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, ctx->st->bitmap.tex_format,
-                          0, width, height, 1, 0);
+                          0, width, height, 1, 0,
+                          PIPE_TEXTURE_USAGE_SAMPLER);
    if (!pt) {
       _mesa_unmap_bitmap_pbo(ctx, unpack);
       return NULL;
@@ -539,7 +540,8 @@ reset_cache(struct st_context *st)
    cache->texture = st_texture_create(st, PIPE_TEXTURE_2D,
                                       st->bitmap.tex_format, 0,
                                       BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
-                                      1, 0);
+                                      1, 0,
+                                      PIPE_TEXTURE_USAGE_SAMPLER);
 
    /* Map the texture surface.
     * Subsequent glBitmap calls will write into the texture image.
diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c
index 9ae53c95f8..8c775ad886 100644
--- a/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -346,7 +346,8 @@ make_texture(struct st_context *st,
       return NULL;
 
    pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height,
-			  1, 0);
+			  1, 0,
+                          PIPE_TEXTURE_USAGE_SAMPLER);
    if (!pt) {
       _mesa_unmap_drawpix_pbo(ctx, unpack);
       return NULL;
@@ -994,7 +995,8 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
    }
 
    pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
-                          width, height, 1, 0);
+                          width, height, 1, 0,
+                          PIPE_TEXTURE_USAGE_SAMPLER);
    if (!pt)
       return;
 
diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c
index b174714171..21d61e2163 100644
--- a/src/mesa/state_tracker/st_cb_fbo.c
+++ b/src/mesa/state_tracker/st_cb_fbo.c
@@ -90,8 +90,8 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
 {
    struct pipe_context *pipe = ctx->st->pipe;
    struct st_renderbuffer *strb = st_renderbuffer(rb);
-
    struct pipe_texture template, *texture;
+   unsigned surface_usage;
 
    /* Free the old surface (and texture if we hold the last
     * reference):
@@ -117,10 +117,15 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
    template.height[0] = height;
    template.depth[0] = 1;
    template.last_level = 0;
-   template.usage = (PIPE_BUFFER_USAGE_CPU_WRITE | 
-                     PIPE_BUFFER_USAGE_CPU_READ |
-                     PIPE_BUFFER_USAGE_GPU_WRITE |
-                     PIPE_BUFFER_USAGE_GPU_READ);
+   template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
+                         PIPE_TEXTURE_USAGE_RENDER_TARGET);
+
+   /* Probably need dedicated flags for surface usage too: 
+    */
+   surface_usage = (PIPE_BUFFER_USAGE_GPU_READ |
+                    PIPE_BUFFER_USAGE_GPU_WRITE |
+                    PIPE_BUFFER_USAGE_CPU_READ |
+                    PIPE_BUFFER_USAGE_CPU_WRITE);
 
    texture = pipe->screen->texture_create( pipe->screen,
                                            &template );
@@ -137,11 +142,13 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
        * to tell the driver to go ahead and allocate the buffer, even
        * if HW doesn't support the format.
        */
-      template.usage = (PIPE_BUFFER_USAGE_CPU_READ |
-                        PIPE_BUFFER_USAGE_CPU_WRITE);
+      template.tex_usage = 0;
+      surface_usage = (PIPE_BUFFER_USAGE_CPU_READ |
+                       PIPE_BUFFER_USAGE_CPU_WRITE);
 
       texture = pipe->screen->texture_create( pipe->screen,
                                               &template );
+
    }
 
    if (!texture) 
@@ -150,7 +157,7 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
    strb->surface = pipe->screen->get_tex_surface( pipe->screen,
                                                   texture,
                                                   0, 0, 0,
-                                                  template.usage );
+                                                  surface_usage );
 
    pipe_texture_reference( &texture, NULL );
 
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index 4cca3364c1..06caa06e77 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -333,7 +333,9 @@ guess_and_alloc_texture(struct st_context *st,
                                  width,
                                  height,
                                  depth,
-                                 comp_byte);
+                                 comp_byte,
+                                 ( PIPE_TEXTURE_USAGE_RENDER_TARGET |
+                                   PIPE_TEXTURE_USAGE_SAMPLER ));
 
    DBG("%s - success\n", __FUNCTION__);
 }
@@ -1501,7 +1503,11 @@ st_finalize_texture(GLcontext *ctx,
                                     firstImage->base.Width2,
                                     firstImage->base.Height2,
                                     firstImage->base.Depth2,
-                                    comp_byte);
+                                    comp_byte,
+
+                                    ( PIPE_TEXTURE_USAGE_RENDER_TARGET |
+                                      PIPE_TEXTURE_USAGE_SAMPLER ));
+
       if (!stObj->pt) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
          return GL_FALSE;
diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c
index d6268fc80c..2b3742d4e5 100644
--- a/src/mesa/state_tracker/st_texture.c
+++ b/src/mesa/state_tracker/st_texture.c
@@ -75,7 +75,8 @@ st_texture_create(struct st_context *st,
 		  GLuint width0,
 		  GLuint height0,
 		  GLuint depth0,
-		  GLuint compress_byte)
+		  GLuint compress_byte,
+                  GLuint usage )
 {
    struct pipe_texture pt, *newtex;
    struct pipe_screen *screen = st->pipe->screen;
@@ -98,6 +99,7 @@ st_texture_create(struct st_context *st,
    pt.depth[0] = depth0;
    pt.compressed = compress_byte ? 1 : 0;
    pt.cpp = pt.compressed ? compress_byte : st_sizeof_format(format);
+   pt.tex_usage = usage;
 
    newtex = screen->texture_create(screen, &pt);
 
diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h
index f6d5733e21..6a9f08ec6b 100644
--- a/src/mesa/state_tracker/st_texture.h
+++ b/src/mesa/state_tracker/st_texture.h
@@ -105,7 +105,8 @@ st_texture_create(struct st_context *st,
                   GLuint width0,
                   GLuint height0,
                   GLuint depth0,
-                  GLuint compress_byte);
+                  GLuint compress_byte,
+                  GLuint tex_usage );
 
 
 /* Check if an image fits into an existing texture object.
-- 
cgit v1.2.3