svga: add helpers for tracking rendering to textures
[mesa.git] / src / gallium / drivers / svga / svga_resource_texture.c
index 4eb1068e2260f7359c0655339a94cf490a775a6e..6d5b4c57c918d178f89c7780d5bd05b516565e64 100644 (file)
@@ -32,6 +32,7 @@
 #include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
+#include "util/u_resource.h"
 
 #include "svga_format.h"
 #include "svga_screen.h"
@@ -133,7 +134,7 @@ svga_transfer_dma(struct svga_context *svga,
       }
    }
    else {
-      unsigned y, h, srcy;
+      int y, h, srcy;
       unsigned blockheight = util_format_get_blockheight(st->base.resource->format);
       h = st->hw_nblocksy * blockheight;
       srcy = 0;
@@ -196,9 +197,6 @@ svga_transfer_dma(struct svga_context *svga,
 }
 
 
-
-
-
 static boolean 
 svga_texture_get_handle(struct pipe_screen *screen,
                                struct pipe_resource *texture,
@@ -220,7 +218,7 @@ svga_texture_destroy(struct pipe_screen *screen,
                     struct pipe_resource *pt)
 {
    struct svga_screen *ss = svga_screen(screen);
-   struct svga_texture *tex = (struct svga_texture *)pt;
+   struct svga_texture *tex = svga_texture(pt);
 
    ss->texture_timestamp++;
 
@@ -232,24 +230,23 @@ svga_texture_destroy(struct pipe_screen *screen,
    SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
    svga_screen_surface_destroy(ss, &tex->key, &tex->handle);
 
+   ss->total_resource_bytes -= tex->size;
+
+   FREE(tex->rendered_to);
    FREE(tex);
 }
 
 
-
-
-
-
-
 /* XXX: Still implementing this as if it was a screen function, but
  * can now modify it to queue transfers on the context.
  */
-static struct pipe_transfer *
-svga_texture_get_transfer(struct pipe_context *pipe,
+static void *
+svga_texture_transfer_map(struct pipe_context *pipe,
                           struct pipe_resource *texture,
                           unsigned level,
                           unsigned usage,
-                          const struct pipe_box *box)
+                          const struct pipe_box *box,
+                          struct pipe_transfer **ptransfer)
 {
    struct svga_context *svga = svga_context(pipe);
    struct svga_screen *ss = svga_screen(pipe->screen);
@@ -259,32 +256,31 @@ svga_texture_get_transfer(struct pipe_context *pipe,
    unsigned nblocksy = util_format_get_nblocksy(texture->format, box->height);
 
    /* We can't map texture storage directly */
-   if (usage & (PIPE_TRANSFER_MAP_DIRECTLY | PIPE_TRANSFER_MAP_PERMANENTLY))
+   if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
       return NULL;
 
-   assert(box->depth == 1);
    st = CALLOC_STRUCT(svga_transfer);
    if (!st)
       return NULL;
 
-   pipe_resource_reference(&st->base.resource, texture);
+   st->base.resource = texture;
    st->base.level = level;
    st->base.usage = usage;
    st->base.box = *box;
    st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
-   st->base.layer_stride = 0;
+   st->base.layer_stride = st->base.stride * nblocksy;
 
    st->hw_nblocksy = nblocksy;
 
    st->hwbuf = svga_winsys_buffer_create(svga,
                                          1, 
                                          0,
-                                         st->hw_nblocksy*st->base.stride);
+                                         st->hw_nblocksy * st->base.stride * box->depth);
    while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
       st->hwbuf = svga_winsys_buffer_create(svga,
                                             1, 
                                             0,
-                                            st->hw_nblocksy*st->base.stride);
+                                            st->hw_nblocksy * st->base.stride * box->depth);
    }
 
    if(!st->hwbuf)
@@ -313,8 +309,22 @@ svga_texture_get_transfer(struct pipe_context *pipe,
       svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
    }
 
-   return &st->base;
+   if (st->swbuf) {
+      *ptransfer = &st->base;
+      return st->swbuf;
+   } else {
+      /* The wait for read transfers already happened when svga_transfer_dma
+       * was called. */
+      void *map = sws->buffer_map(sws, st->hwbuf, usage);
+      if (!map)
+         goto fail;
+
+      *ptransfer = &st->base;
+      return map;
+   }
 
+fail:
+   FREE(st->swbuf);
 no_swbuf:
    sws->buffer_destroy(sws, st->hwbuf);
 no_hwbuf:
@@ -323,26 +333,6 @@ no_hwbuf:
 }
 
 
-/* XXX: Still implementing this as if it was a screen function, but
- * can now modify it to queue transfers on the context.
- */
-static void *
-svga_texture_transfer_map( struct pipe_context *pipe,
-                          struct pipe_transfer *transfer )
-{
-   struct svga_screen *ss = svga_screen(pipe->screen);
-   struct svga_winsys_screen *sws = ss->sws;
-   struct svga_transfer *st = svga_transfer(transfer);
-
-   if(st->swbuf)
-      return st->swbuf;
-   else
-      /* The wait for read transfers already happened when svga_transfer_dma
-       * was called. */
-      return sws->buffer_map(sws, st->hwbuf, transfer->usage);
-}
-
-
 /* XXX: Still implementing this as if it was a screen function, but
  * can now modify it to queue transfers on the context.
  */
@@ -350,24 +340,14 @@ static void
 svga_texture_transfer_unmap(struct pipe_context *pipe,
                            struct pipe_transfer *transfer)
 {
+   struct svga_context *svga = svga_context(pipe);
    struct svga_screen *ss = svga_screen(pipe->screen);
    struct svga_winsys_screen *sws = ss->sws;
    struct svga_transfer *st = svga_transfer(transfer);
-   
+   struct svga_texture *tex = svga_texture(transfer->resource);
+
    if(!st->swbuf)
       sws->buffer_unmap(sws, st->hwbuf);
-}
-
-
-static void
-svga_texture_transfer_destroy(struct pipe_context *pipe,
-                             struct pipe_transfer *transfer)
-{
-   struct svga_context *svga = svga_context(pipe);
-   struct svga_texture *tex = svga_texture(transfer->resource);
-   struct svga_screen *ss = svga_screen(pipe->screen);
-   struct svga_winsys_screen *sws = ss->sws;
-   struct svga_transfer *st = svga_transfer(transfer);
 
    if (st->base.usage & PIPE_TRANSFER_WRITE) {
       SVGA3dSurfaceDMAFlags flags;
@@ -382,29 +362,23 @@ svga_texture_transfer_destroy(struct pipe_context *pipe,
 
       svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
       ss->texture_timestamp++;
-      tex->view_age[transfer->level] = ++(tex->age);
+      svga_age_texture_view(tex, transfer->level);
       if (transfer->resource->target == PIPE_TEXTURE_CUBE)
-         tex->defined[transfer->box.z][transfer->level] = TRUE;
+         svga_define_texture_level(tex, transfer->box.z, transfer->level);
       else
-         tex->defined[0][transfer->level] = TRUE;
+         svga_define_texture_level(tex, 0, transfer->level);
    }
 
-   pipe_resource_reference(&st->base.resource, NULL);
    FREE(st->swbuf);
    sws->buffer_destroy(sws, st->hwbuf);
    FREE(st);
 }
 
 
-
-
-
 struct u_resource_vtbl svga_texture_vtbl = 
 {
    svga_texture_get_handle,          /* get_handle */
    svga_texture_destroy,             /* resource_destroy */
-   svga_texture_get_transfer,        /* get_transfer */
-   svga_texture_transfer_destroy,     /* transfer_destroy */
    svga_texture_transfer_map,        /* transfer_map */
    u_default_transfer_flush_region,   /* transfer_flush_region */
    svga_texture_transfer_unmap,              /* transfer_unmap */
@@ -412,8 +386,6 @@ struct u_resource_vtbl svga_texture_vtbl =
 };
 
 
-
-
 struct pipe_resource *
 svga_texture_create(struct pipe_screen *screen,
                     const struct pipe_resource *template)
@@ -446,8 +418,11 @@ svga_texture_create(struct pipe_screen *screen,
       tex->key.numFaces = 1;
    }
 
-   /* XXX: Disabled for now */
-   tex->key.cachable = 0;
+   if (template->target == PIPE_TEXTURE_3D) {
+      tex->key.flags |= SVGA3D_SURFACE_VOLUME;
+   }
+
+   tex->key.cachable = 1;
 
    if (template->bind & PIPE_BIND_SAMPLER_VIEW)
       tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
@@ -467,16 +442,19 @@ svga_texture_create(struct pipe_screen *screen,
    }
 
    /* 
-    * XXX: Never pass the SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
+    * Note: Previously we never passed the
+    * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
     * know beforehand whether a texture will be used as a rendertarget or not
     * and it always requests PIPE_BIND_RENDER_TARGET, therefore
     * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
+    *
+    * However, this was changed since other state trackers
+    * (XA for example) uses it accurately and certain device versions
+    * relies on it in certain situations to render correctly.
     */
-#if 0
    if((template->bind & PIPE_BIND_RENDER_TARGET) &&
       !util_format_is_s3tc(template->format))
       tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
-#endif
    
    if(template->bind & PIPE_BIND_DEPTH_STENCIL)
       tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
@@ -495,17 +473,24 @@ svga_texture_create(struct pipe_screen *screen,
    debug_reference(&tex->b.b.reference,
                    (debug_reference_descriptor)debug_describe_resource, 0);
 
+   tex->size = util_resource_size(template);
+   svgascreen->total_resource_bytes += tex->size;
+
+   tex->rendered_to = CALLOC(template->depth0 * template->array_size,
+                             sizeof(tex->rendered_to[0]));
+   if (!tex->rendered_to)
+      goto error2;
+
    return &tex->b.b;
 
 error2:
+   FREE(tex->rendered_to);
    FREE(tex);
 error1:
    return NULL;
 }
 
 
-
-
 struct pipe_resource *
 svga_texture_from_handle(struct pipe_screen *screen,
                         const struct pipe_resource *template,
@@ -553,19 +538,12 @@ svga_texture_from_handle(struct pipe_screen *screen,
    pipe_reference_init(&tex->b.b.reference, 1);
    tex->b.b.screen = screen;
 
-   if (format == SVGA3D_X8R8G8B8)
-      tex->b.b.format = PIPE_FORMAT_B8G8R8X8_UNORM;
-   else if (format == SVGA3D_A8R8G8B8)
-      tex->b.b.format = PIPE_FORMAT_B8G8R8A8_UNORM;
-   else {
-      /* ?? */
-   }
-
    SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);
 
    tex->key.cachable = 0;
    tex->handle = srf;
 
+   tex->rendered_to = CALLOC(1, sizeof(tex->rendered_to[0]));
+
    return &tex->b.b;
 }
-