nvc0: add support for linear and buffer textures and RTs
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Tue, 18 Oct 2011 10:08:19 +0000 (12:08 +0200)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Fri, 21 Oct 2011 21:00:40 +0000 (23:00 +0200)
src/gallium/drivers/nv50/nv50_miptree.c
src/gallium/drivers/nv50/nv50_resource.c
src/gallium/drivers/nv50/nv50_resource.h
src/gallium/drivers/nvc0/nvc0_miptree.c
src/gallium/drivers/nvc0/nvc0_resource.c
src/gallium/drivers/nvc0/nvc0_state_validate.c
src/gallium/drivers/nvc0/nvc0_surface.c
src/gallium/drivers/nvc0/nvc0_tex.c

index 47090e1..76b6059 100644 (file)
@@ -424,13 +424,3 @@ nv50_miptree_surface_new(struct pipe_context *pipe,
 
    return &ns->base;
 }
-
-void
-nv50_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
-{
-   struct nv50_surface *s = nv50_surface(ps);
-
-   pipe_resource_reference(&ps->texture, NULL);
-
-   FREE(s);
-}
index 1ae4d70..a66a6a0 100644 (file)
@@ -1,8 +1,11 @@
 
 #include "pipe/p_context.h"
-#include "nv50_resource.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+
 #include "nouveau/nouveau_screen.h"
 
+#include "nv50_resource.h"
 
 static struct pipe_resource *
 nv50_resource_create(struct pipe_screen *screen,
@@ -27,6 +30,59 @@ nv50_resource_from_handle(struct pipe_screen * screen,
       return nv50_miptree_from_handle(screen, templ, whandle);
 }
 
+struct pipe_surface *
+nv50_surface_from_buffer(struct pipe_context *pipe,
+                        struct pipe_resource *pbuf,
+                        const struct pipe_surface *templ)
+{
+   struct nv50_surface *sf = CALLOC_STRUCT(nv50_surface);
+   if (!sf)
+      return NULL;
+
+   pipe_reference_init(&sf->base.reference, 1);
+   pipe_resource_reference(&sf->base.texture, pbuf);
+
+   sf->base.format = templ->format;
+   sf->base.usage = templ->usage;
+   sf->base.u.buf.first_element = templ->u.buf.first_element;
+   sf->base.u.buf.last_element = templ->u.buf.last_element;
+
+   sf->offset =
+      templ->u.buf.first_element * util_format_get_blocksize(sf->base.format);
+
+   sf->offset &= ~0x7f; /* FIXME: RT_ADDRESS requires 128 byte alignment */
+
+   sf->width = templ->u.buf.last_element - templ->u.buf.first_element + 1;
+   sf->height = 1;
+   sf->depth = 1;
+
+   sf->base.width = sf->width;
+   sf->base.height = sf->height;
+
+   sf->base.context = pipe;
+   return &sf->base;
+}
+
+static struct pipe_surface *
+nv50_surface_create(struct pipe_context *pipe,
+                   struct pipe_resource *pres,
+                   const struct pipe_surface *templ)
+{
+   if (unlikely(pres->target == PIPE_BUFFER))
+      return nv50_surface_from_buffer(pipe, pres, templ);
+   return nv50_miptree_surface_new(pipe, pres, templ);
+}
+
+void
+nv50_surface_destroy(struct pipe_context *pipe, struct pipe_surface *ps)
+{
+   struct nv50_surface *s = nv50_surface(ps);
+
+   pipe_resource_reference(&ps->texture, NULL);
+
+   FREE(s);
+}
+
 void
 nv50_init_resource_functions(struct pipe_context *pcontext)
 {
@@ -36,8 +92,8 @@ nv50_init_resource_functions(struct pipe_context *pcontext)
    pcontext->transfer_unmap = u_transfer_unmap_vtbl;
    pcontext->transfer_destroy = u_transfer_destroy_vtbl;
    pcontext->transfer_inline_write = u_transfer_inline_write_vtbl;
-   pcontext->create_surface = nv50_miptree_surface_new;
-   pcontext->surface_destroy = nv50_miptree_surface_del;
+   pcontext->create_surface = nv50_surface_create;
+   pcontext->surface_destroy = nv50_surface_destroy;
 }
 
 void
index 66d2120..50cc2af 100644 (file)
@@ -129,7 +129,12 @@ struct nv50_surface *
 nv50_surface_from_miptree(struct nv50_miptree *mt,
                           const struct pipe_surface *templ);
 
+struct pipe_surface *
+nv50_surface_from_buffer(struct pipe_context *pipe,
+                         struct pipe_resource *pt,
+                         const struct pipe_surface *templ);
+
 void
-nv50_miptree_surface_del(struct pipe_context *, struct pipe_surface *);
+nv50_surface_destroy(struct pipe_context *, struct pipe_surface *);
 
 #endif /* __NV50_RESOURCE_H__ */
index 6cdc8ab..a9d2c85 100644 (file)
@@ -149,6 +149,9 @@ nvc0_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed)
    if (mt->base.base.bind & PIPE_BIND_SCANOUT)
       tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
 
+   if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
+      tile_flags &= ~0xff00;
+
    return tile_flags;
 }
 
index a028972..e8d83ca 100644 (file)
@@ -31,6 +31,16 @@ nvc0_resource_from_handle(struct pipe_screen * screen,
    }
 }
 
+static struct pipe_surface *
+nvc0_surface_create(struct pipe_context *pipe,
+                    struct pipe_resource *pres,
+                    const struct pipe_surface *templ)
+{
+   if (unlikely(pres->target == PIPE_BUFFER))
+      return nv50_surface_from_buffer(pipe, pres, templ);
+   return nvc0_miptree_surface_new(pipe, pres, templ);
+}
+
 void
 nvc0_init_resource_functions(struct pipe_context *pcontext)
 {
@@ -40,8 +50,8 @@ nvc0_init_resource_functions(struct pipe_context *pcontext)
    pcontext->transfer_unmap = u_transfer_unmap_vtbl;
    pcontext->transfer_destroy = u_transfer_destroy_vtbl;
    pcontext->transfer_inline_write = u_transfer_inline_write_vtbl;
-   pcontext->create_surface = nvc0_miptree_surface_new;
-   pcontext->surface_destroy = nv50_miptree_surface_del;
+   pcontext->create_surface = nvc0_surface_create;
+   pcontext->surface_destroy = nv50_surface_destroy;
 }
 
 void
index 5cf68c7..e60ed97 100644 (file)
@@ -73,33 +73,56 @@ nvc0_validate_fb(struct nvc0_context *nvc0)
     MARK_RING(chan, 9 * fb->nr_cbufs, 2 * fb->nr_cbufs);
 
     for (i = 0; i < fb->nr_cbufs; ++i) {
-        struct nv50_miptree *mt = nv50_miptree(fb->cbufs[i]->texture);
         struct nv50_surface *sf = nv50_surface(fb->cbufs[i]);
-        struct nouveau_bo *bo = mt->base.bo;
-        uint32_t offset = sf->offset;
+        struct nv04_resource *res = nv04_resource(sf->base.texture);
+        struct nouveau_bo *bo = res->bo;
+        uint32_t offset = sf->offset + res->offset;
 
         BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(i)), 9);
-        OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
-        OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
-        OUT_RING  (chan, sf->width);
-        OUT_RING  (chan, sf->height);
-        OUT_RING  (chan, nvc0_format_table[sf->base.format].rt);
-        OUT_RING  (chan, (mt->layout_3d << 16) |
-                   mt->level[sf->base.u.tex.level].tile_mode);
-        OUT_RING  (chan, sf->base.u.tex.first_layer + sf->depth);
-        OUT_RING  (chan, mt->layer_stride >> 2);
-        OUT_RING  (chan, sf->base.u.tex.first_layer);
-
-        ms_mode = mt->ms_mode;
-
-        if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
+        OUT_RELOCh(chan, res->bo, offset, res->domain | NOUVEAU_BO_RDWR);
+        OUT_RELOCl(chan, res->bo, offset, res->domain | NOUVEAU_BO_RDWR);
+        if (likely(nouveau_bo_tile_layout(bo))) {
+           struct nv50_miptree *mt = nv50_miptree(sf->base.texture);
+
+           assert(sf->base.texture->target != PIPE_BUFFER);
+
+           OUT_RING(chan, sf->width);
+           OUT_RING(chan, sf->height);
+           OUT_RING(chan, nvc0_format_table[sf->base.format].rt);
+           OUT_RING(chan, (mt->layout_3d << 16) |
+                    mt->level[sf->base.u.tex.level].tile_mode);
+           OUT_RING(chan, sf->base.u.tex.first_layer + sf->depth);
+           OUT_RING(chan, mt->layer_stride >> 2);
+           OUT_RING(chan, sf->base.u.tex.first_layer);
+
+           ms_mode = mt->ms_mode;
+        } else {
+           if (res->base.target == PIPE_BUFFER) {
+              OUT_RING(chan, 262144);
+              OUT_RING(chan, 1);
+           } else {
+              OUT_RING(chan, nv50_miptree(sf->base.texture)->level[0].pitch);
+              OUT_RING(chan, sf->height);
+           }
+           OUT_RING(chan, nvc0_format_table[sf->base.format].rt);
+           OUT_RING(chan, 1 << 12);
+           OUT_RING(chan, 1);
+           OUT_RING(chan, 0);
+           OUT_RING(chan, 0);
+
+           nvc0_resource_fence(res, NOUVEAU_BO_WR);
+
+           assert(!fb->zsbuf);
+        }
+
+        if (res->status & NOUVEAU_BUFFER_STATUS_GPU_READING)
            serialize = TRUE;
-        mt->base.status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
-        mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
+        res->status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
+        res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
 
         /* only register for writing, otherwise we'd always serialize here */
-        nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, &mt->base,
-                                 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+        nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, res,
+                                 res->domain | NOUVEAU_BO_WR);
     }
 
     if (fb->zsbuf) {
index 5c4e1aa..f807535 100644 (file)
@@ -271,48 +271,69 @@ nvc0_clear_render_target(struct pipe_context *pipe,
                          unsigned dstx, unsigned dsty,
                          unsigned width, unsigned height)
 {
-       struct nvc0_context *nv50 = nvc0_context(pipe);
-       struct nvc0_screen *screen = nv50->screen;
-       struct nouveau_channel *chan = screen->base.channel;
-       struct nv50_miptree *mt = nv50_miptree(dst->texture);
-       struct nv50_surface *sf = nv50_surface(dst);
-       struct nouveau_bo *bo = mt->base.bo;
-       unsigned z;
+   struct nvc0_context *nv50 = nvc0_context(pipe);
+   struct nvc0_screen *screen = nv50->screen;
+   struct nouveau_channel *chan = screen->base.channel;
+   struct nv50_surface *sf = nv50_surface(dst);
+   struct nv04_resource *res = nv04_resource(sf->base.texture);
+   unsigned z;
 
-       BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
-       OUT_RINGf (chan, color->f[0]);
-       OUT_RINGf (chan, color->f[1]);
-       OUT_RINGf (chan, color->f[2]);
-       OUT_RINGf (chan, color->f[3]);
+   BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
+   OUT_RINGf (chan, color->f[0]);
+   OUT_RINGf (chan, color->f[1]);
+   OUT_RINGf (chan, color->f[2]);
+   OUT_RINGf (chan, color->f[3]);
 
-       if (MARK_RING(chan, 18, 2))
-               return;
+   if (MARK_RING(chan, 18, 2))
+      return;
 
-       BEGIN_RING(chan, RING_3D(SCREEN_SCISSOR_HORIZ), 2);
-       OUT_RING  (chan, ( width << 16) | dstx);
-       OUT_RING  (chan, (height << 16) | dsty);
+   BEGIN_RING(chan, RING_3D(SCREEN_SCISSOR_HORIZ), 2);
+   OUT_RING  (chan, ( width << 16) | dstx);
+   OUT_RING  (chan, (height << 16) | dsty);
+
+   BEGIN_RING(chan, RING_3D(RT_CONTROL), 1);
+   OUT_RING  (chan, 1);
+   BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 9);
+   OUT_RESRCh(chan, res, sf->offset, NOUVEAU_BO_WR);
+   OUT_RESRCl(chan, res, sf->offset, NOUVEAU_BO_WR);
+   if (likely(nouveau_bo_tile_layout(res->bo))) {
+      struct nv50_miptree *mt = nv50_miptree(dst->texture);
+
+      OUT_RING(chan, sf->width);
+      OUT_RING(chan, sf->height);
+      OUT_RING(chan, nvc0_format_table[dst->format].rt);
+      OUT_RING(chan, (mt->layout_3d << 16) |
+               mt->level[sf->base.u.tex.level].tile_mode);
+      OUT_RING(chan, dst->u.tex.first_layer + sf->depth);
+      OUT_RING(chan, mt->layer_stride >> 2);
+      OUT_RING(chan, dst->u.tex.first_layer);
+   } else {
+      if (res->base.target == PIPE_BUFFER) {
+         OUT_RING(chan, 262144);
+         OUT_RING(chan, 1);
+      } else {
+         OUT_RING(chan, nv50_miptree(&res->base)->level[0].pitch);
+         OUT_RING(chan, sf->height);
+      }
+      OUT_RING(chan, nvc0_format_table[sf->base.format].rt);
+      OUT_RING(chan, 1 << 12);
+      OUT_RING(chan, 1);
+      OUT_RING(chan, 0);
+      OUT_RING(chan, 0);
 
-       BEGIN_RING(chan, RING_3D(RT_CONTROL), 1);
-       OUT_RING  (chan, 1);
-       BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 9);
-       OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-       OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-       OUT_RING  (chan, sf->width);
-       OUT_RING  (chan, sf->height);
-       OUT_RING  (chan, nvc0_format_table[dst->format].rt);
-       OUT_RING  (chan, (mt->layout_3d << 16) |
-              mt->level[sf->base.u.tex.level].tile_mode);
-       OUT_RING  (chan, dst->u.tex.first_layer + sf->depth);
-       OUT_RING  (chan, mt->layer_stride >> 2);
-       OUT_RING  (chan, dst->u.tex.first_layer);
+      IMMED_RING(chan, RING_3D(ZETA_ENABLE), 0);
 
-       for (z = 0; z < sf->depth; ++z) {
-               BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
-               OUT_RING  (chan, 0x3c |
-                          (z << NVC0_3D_CLEAR_BUFFERS_LAYER__SHIFT));
-       }
+      /* tiled textures don't have to be fenced, they're not mapped directly */
+      nvc0_resource_fence(res, NOUVEAU_BO_WR);
+   }
 
-       nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
+   for (z = 0; z < sf->depth; ++z) {
+      BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
+      OUT_RING  (chan, 0x3c |
+                 (z << NVC0_3D_CLEAR_BUFFERS_LAYER__SHIFT));
+   }
+
+   nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
 }
 
 static void
index a4573d7..0a1bc37 100644 (file)
@@ -60,7 +60,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    uint32_t swz[4];
    uint32_t depth;
    struct nv50_tic_entry *view;
-   struct nv50_miptree *mt = nv50_miptree(texture);
+   struct nv50_miptree *mt;
    boolean tex_int;
 
    view = MALLOC_STRUCT(nv50_tic_entry);
@@ -104,6 +104,32 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
       tic[2] |= NV50_TIC_2_COLORSPACE_SRGB;
 
+   /* check for linear storage type */
+   if (unlikely(!nouveau_bo_tile_layout(nv04_resource(texture)->bo))) {
+      if (texture->target == PIPE_BUFFER) {
+         tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER;
+         tic[1] = /* address offset */
+            view->pipe.u.buf.first_element * desc->block.bits / 8;
+         tic[3] = 0;
+         tic[4] = /* width */
+            view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1;
+        tic[5] = 0;
+      } else {
+         mt = nv50_miptree(texture);
+         /* must be 2D texture without mip maps */
+         tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT;
+         if (texture->target != PIPE_TEXTURE_RECT)
+            tic[2] |= NV50_TIC_2_NORMALIZED_COORDS;
+         tic[3] = mt->level[0].pitch;
+         tic[4] = mt->base.base.width0;
+         tic[5] = (1 << 16) | mt->base.base.height0;
+      }
+      tic[6] =
+      tic[7] = 0;
+      return &view->pipe;
+   }
+   mt = nv50_miptree(texture);
+
    if (mt->base.base.target != PIPE_TEXTURE_RECT)
       tic[2] |= NV50_TIC_2_NORMALIZED_COORDS;
 
@@ -147,9 +173,6 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    case PIPE_TEXTURE_2D_ARRAY:
       tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY;
       break;
-   case PIPE_BUFFER:
-      tic[2] |= NV50_TIC_2_TARGET_BUFFER | NV50_TIC_2_LINEAR;
-      break;
    default:
       NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target);
       return FALSE;
@@ -196,10 +219,10 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s)
          OUT_RING  (chan, (i << 1) | 0);
          continue;
       }
-      res = &nv50_miptree(tic->pipe.texture)->base;
+      res = nv04_resource(tic->pipe.texture);
 
       if (tic->id < 0) {
-         uint32_t offset = tic->tic[1];
+         uint32_t offset = res->offset + tic->tic[1];
 
          tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic);
 
@@ -214,8 +237,8 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s)
          OUT_RING  (chan, 0x100111);
          BEGIN_RING_NI(chan, RING_MF(DATA), 8);
          OUT_RING  (chan, tic->tic[0]);
-         OUT_RELOCl(chan, res->bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
-         OUT_RELOC (chan, res->bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
+         OUT_RELOCl(chan, res->bo, offset, res->domain | NOUVEAU_BO_RD);
+         OUT_RELOC (chan, res->bo, offset, res->domain | NOUVEAU_BO_RD |
                     NOUVEAU_BO_HIGH | NOUVEAU_BO_OR, tic->tic[2], tic->tic[2]);
          OUT_RINGp (chan, &tic->tic[3], 5);
 
@@ -231,7 +254,7 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s)
       res->status |=  NOUVEAU_BUFFER_STATUS_GPU_READING;
 
       nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_TEXTURES, res,
-                               NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+                               res->domain | NOUVEAU_BO_RD);
 
       BEGIN_RING(chan, RING_3D(BIND_TIC(s)), 1);
       OUT_RING  (chan, (tic->id << 9) | (i << 1) | 1);