gallium: Add texture usage flags, special-case allocation of display targets
authorKeith Whitwell <keith@tungstengraphics.com>
Fri, 2 May 2008 15:46:31 +0000 (16:46 +0100)
committerKeith Whitwell <keith@tungstengraphics.com>
Fri, 2 May 2008 15:46:31 +0000 (16:46 +0100)
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
src/gallium/drivers/softpipe/sp_texture.h
src/gallium/include/pipe/p_state.h
src/mesa/state_tracker/st_atom_pixeltransfer.c
src/mesa/state_tracker/st_cb_bitmap.c
src/mesa/state_tracker/st_cb_drawpixels.c
src/mesa/state_tracker/st_cb_fbo.c
src/mesa/state_tracker/st_cb_texture.c
src/mesa/state_tracker/st_texture.c
src/mesa/state_tracker/st_texture.h

index 2b31cd4f25120e4f8a906be88a6bb6a7119bacd0..599ff2ac458cb8dc28201fe9d4fdd6895543db7f 100644 (file)
@@ -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;
 }
index 2ba093320dc8934d9b8ed546bdfe20d2b5589784..779a9d8fc970c0bf070886fe312858b44aa4a235 100644 (file)
@@ -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;
 };
 
 
index 277ee4b31905dabbd60134f6ce030e0a768d944b..d7565dff96059f8052284319fe24442d5ec13468 100644 (file)
@@ -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:
     */
index 0c32d53c4ab1eb7ef8f7ec5703b73243139173ee..e500ac8684df9e0091df70259d9aed5163a0565c 100644 (file)
@@ -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;
 }
 
index 873b765c2c2719bbf99003d6a241858246e4d0a2..f816e59104227b3d1269b00855c3b4d0d0f33ebe 100644 (file)
@@ -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.
index 9ae53c95f8656f0703a83c03344b3afea11859d9..8c775ad8864e3b21a66487e2e3dbeea3dee6e1ae 100644 (file)
@@ -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;
 
index b1747141710b15ef1ef2a5286d36a900b0a5ef30..21d61e216381ae2c0700d900b8d615122c9cc35d 100644 (file)
@@ -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 );
 
index 4cca3364c150f1759b4c0b4636f315a74fbe5eac..06caa06e7767b8ab1b8ffbca358862232e9a9ffb 100644 (file)
@@ -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;
index d6268fc80ca350d3ae1eea5b909417499cb65c89..2b3742d4e5b542e6261007a7bdd63e665c71aa25 100644 (file)
@@ -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);
 
index f6d5733e210c07fb3b415ece242ba14bc33a9fb5..6a9f08ec6b79044cf1e693e6f46497d9ca187fd8 100644 (file)
@@ -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.