Mesa (master): nv50,nvc0: add support for multi-sample resources

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Thu Jul 14 10:51:50 UTC 2011


Module: Mesa
Branch: master
Commit: b2dcf880e8bcd61be59602f5a2d18c77a5fc60c1
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b2dcf880e8bcd61be59602f5a2d18c77a5fc60c1

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Mon Jul 11 18:02:27 2011 +0200

nv50,nvc0: add support for multi-sample resources

---

 src/gallium/drivers/nv50/nv50_context.h        |    6 ++
 src/gallium/drivers/nv50/nv50_miptree.c        |    1 -
 src/gallium/drivers/nv50/nv50_resource.h       |   16 +++++
 src/gallium/drivers/nv50/nv50_screen.c         |    4 +-
 src/gallium/drivers/nv50/nv50_state.c          |   13 ++++
 src/gallium/drivers/nv50/nv50_state_validate.c |   29 ++++++++
 src/gallium/drivers/nv50/nv50_stateobj.h       |    4 +-
 src/gallium/drivers/nv50/nv50_surface.c        |   66 +++++++++++++++----
 src/gallium/drivers/nv50/nv50_tex.c            |    6 +-
 src/gallium/drivers/nv50/nv50_transfer.c       |   82 ++++++++++++++---------
 src/gallium/drivers/nv50/nv50_transfer.h       |   21 ++-----
 src/gallium/drivers/nvc0/nvc0_3d.xml.h         |    5 ++
 src/gallium/drivers/nvc0/nvc0_context.h        |    7 ++
 src/gallium/drivers/nvc0/nvc0_miptree.c        |    1 -
 src/gallium/drivers/nvc0/nvc0_resource.h       |   16 +++++
 src/gallium/drivers/nvc0/nvc0_screen.c         |    2 +-
 src/gallium/drivers/nvc0/nvc0_state.c          |   12 ++++
 src/gallium/drivers/nvc0/nvc0_state_validate.c |   30 +++++++++
 src/gallium/drivers/nvc0/nvc0_stateobj.h       |    4 +-
 src/gallium/drivers/nvc0/nvc0_surface.c        |   84 ++++++++----------------
 src/gallium/drivers/nvc0/nvc0_tex.c            |   15 ++++-
 src/gallium/drivers/nvc0/nvc0_transfer.c       |   53 +++++----------
 src/gallium/drivers/nvc0/nvc0_transfer.h       |   44 ------------
 23 files changed, 308 insertions(+), 213 deletions(-)

diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h
index 4e141a6..c1226d5 100644
--- a/src/gallium/drivers/nv50/nv50_context.h
+++ b/src/gallium/drivers/nv50/nv50_context.h
@@ -18,6 +18,7 @@
 #include "nv50_screen.h"
 #include "nv50_program.h"
 #include "nv50_resource.h"
+#include "nv50_transfer.h"
 
 #include "nouveau/nouveau_context.h"
 #include "nouveau/nv_object.xml.h"
@@ -188,6 +189,11 @@ nv50_create_sampler_view(struct pipe_context *,
 
 /* nv50_transfer.c */
 void
+nv50_m2mf_transfer_rect(struct pipe_screen *pscreen,
+                        const struct nv50_m2mf_rect *dst,
+                        const struct nv50_m2mf_rect *src,
+                        uint32_t nblocksx, uint32_t nblocksy);
+void
 nv50_sifc_linear_u8(struct nouveau_context *pipe,
                     struct nouveau_bo *dst, unsigned offset, unsigned domain,
                     unsigned size, void *data);
diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c
index fcb9ca3..115a98d 100644
--- a/src/gallium/drivers/nv50/nv50_miptree.c
+++ b/src/gallium/drivers/nv50/nv50_miptree.c
@@ -27,7 +27,6 @@
 
 #include "nv50_context.h"
 #include "nv50_resource.h"
-#include "nv50_transfer.h"
 
 static INLINE uint32_t
 nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz)
diff --git a/src/gallium/drivers/nv50/nv50_resource.h b/src/gallium/drivers/nv50/nv50_resource.h
index a771edf..66d2120 100644
--- a/src/gallium/drivers/nv50/nv50_resource.h
+++ b/src/gallium/drivers/nv50/nv50_resource.h
@@ -107,6 +107,22 @@ nv50_miptree_surface_new(struct pipe_context *,
                          struct pipe_resource *,
                          const struct pipe_surface *templ);
 
+struct pipe_transfer *
+nv50_miptree_transfer_new(struct pipe_context *pcontext,
+                          struct pipe_resource *pt,
+                          unsigned level,
+                          unsigned usage,
+                          const struct pipe_box *box);
+void
+nv50_miptree_transfer_del(struct pipe_context *pcontext,
+                          struct pipe_transfer *ptx);
+void *
+nv50_miptree_transfer_map(struct pipe_context *pcontext,
+                          struct pipe_transfer *ptx);
+void
+nv50_miptree_transfer_unmap(struct pipe_context *pcontext,
+                            struct pipe_transfer *ptx);
+
 #endif /* __NVC0_RESOURCE_H__ */
 
 struct nv50_surface *
diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c
index 4cda303..a697ff5 100644
--- a/src/gallium/drivers/nv50/nv50_screen.c
+++ b/src/gallium/drivers/nv50/nv50_screen.c
@@ -43,7 +43,9 @@ nv50_screen_is_format_supported(struct pipe_screen *pscreen,
                                 unsigned sample_count,
                                 unsigned bindings)
 {
-   if (sample_count > 1)
+   if (sample_count > 2 && sample_count != 4 && sample_count != 8)
+      return FALSE;
+   if (sample_count == 8 && util_format_get_blocksizebits(format) >= 128)
       return FALSE;
 
    if (!util_format_is_supported(format, bindings))
diff --git a/src/gallium/drivers/nv50/nv50_state.c b/src/gallium/drivers/nv50/nv50_state.c
index fb125f3..49ea646 100644
--- a/src/gallium/drivers/nv50/nv50_state.c
+++ b/src/gallium/drivers/nv50/nv50_state.c
@@ -119,6 +119,7 @@ nv50_blend_state_create(struct pipe_context *pipe,
    struct nv50_blend_stateobj *so = CALLOC_STRUCT(nv50_blend_stateobj);
    int i;
    boolean emit_common_func = cso->rt[0].blend_enable;
+   uint32_t ms;
 
    if (nv50_context(pipe)->screen->tesla->grclass >= NVA3_3D) {
       SB_BEGIN_3D(so, BLEND_INDEPENDENT, 1);
@@ -190,6 +191,15 @@ nv50_blend_state_create(struct pipe_context *pipe,
       SB_DATA    (so, nv50_colormask(cso->rt[0].colormask));
    }
 
+   ms = 0;
+   if (cso->alpha_to_coverage)
+      ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE;
+   if (cso->alpha_to_one)
+      ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE;
+
+   SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1);
+   SB_DATA    (so, ms);
+
    assert(so->size <= (sizeof(so->state) / sizeof(so->state[0])));
    return so;
 }
@@ -237,6 +247,9 @@ nv50_rasterizer_state_create(struct pipe_context *pipe,
    SB_BEGIN_3D(so, FRAG_COLOR_CLAMP_EN, 1);
    SB_DATA    (so, cso->clamp_fragment_color ? 0x11111111 : 0x00000000);
 
+   SB_BEGIN_3D(so, MULTISAMPLE_ENABLE, 1);
+   SB_DATA    (so, cso->multisample);
+
    SB_BEGIN_3D(so, LINE_WIDTH, 1);
    SB_DATA    (so, fui(cso->line_width));
    SB_BEGIN_3D(so, LINE_SMOOTH_ENABLE, 1);
diff --git a/src/gallium/drivers/nv50/nv50_state_validate.c b/src/gallium/drivers/nv50/nv50_state_validate.c
index d29c1e9..8b0b08f 100644
--- a/src/gallium/drivers/nv50/nv50_state_validate.c
+++ b/src/gallium/drivers/nv50/nv50_state_validate.c
@@ -8,6 +8,7 @@ nv50_validate_fb(struct nv50_context *nv50)
    struct nouveau_channel *chan = nv50->screen->base.channel;
    struct pipe_framebuffer_state *fb = &nv50->framebuffer;
    unsigned i;
+   unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
    boolean serialize = FALSE;
 
    nv50_bufctx_reset(nv50, NV50_BUFCTX_FRAME);
@@ -38,6 +39,8 @@ nv50_validate_fb(struct nv50_context *nv50)
       BEGIN_RING(chan, RING_3D(RT_ARRAY_MODE), 1);
       OUT_RING  (chan, sf->depth);
 
+      ms_mode = mt->ms_mode;
+
       if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
          serialize = TRUE;
       mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
@@ -69,6 +72,8 @@ nv50_validate_fb(struct nv50_context *nv50)
       OUT_RING  (chan, sf->height);
       OUT_RING  (chan, (unk << 16) | sf->depth);
 
+      ms_mode = mt->ms_mode;
+
       if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
          serialize = TRUE;
       mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
@@ -81,6 +86,9 @@ nv50_validate_fb(struct nv50_context *nv50)
       OUT_RING  (chan, 0);
    }
 
+   BEGIN_RING(chan, RING_3D(MULTISAMPLE_MODE), 1);
+   OUT_RING  (chan, ms_mode);
+
    BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2);
    OUT_RING  (chan, fb->width << 16);
    OUT_RING  (chan, fb->height << 16);
@@ -258,6 +266,26 @@ nv50_validate_rasterizer(struct nv50_context *nv50)
 }
 
 static void
+nv50_validate_sample_mask(struct nv50_context *nv50)
+{
+   struct nouveau_channel *chan = nv50->screen->base.channel;
+
+   unsigned mask[4] =
+   {
+      nv50->sample_mask & 0xffff,
+      nv50->sample_mask & 0xffff,
+      nv50->sample_mask & 0xffff,
+      nv50->sample_mask & 0xffff
+   };
+
+   BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4);
+   OUT_RING  (chan, mask[0]);
+   OUT_RING  (chan, mask[1]);
+   OUT_RING  (chan, mask[2]);
+   OUT_RING  (chan, mask[3]);
+}
+
+static void
 nv50_switch_pipe_context(struct nv50_context *ctx_to)
 {
    struct nv50_context *ctx_from = ctx_to->screen->cur_ctx;
@@ -292,6 +320,7 @@ static struct state_validate {
     { nv50_validate_fb,            NV50_NEW_FRAMEBUFFER },
     { nv50_validate_blend,         NV50_NEW_BLEND },
     { nv50_validate_zsa,           NV50_NEW_ZSA },
+    { nv50_validate_sample_mask,   NV50_NEW_SAMPLE_MASK },
     { nv50_validate_rasterizer,    NV50_NEW_RASTERIZER },
     { nv50_validate_blend_colour,  NV50_NEW_BLEND_COLOUR },
     { nv50_validate_stencil_ref,   NV50_NEW_STENCIL_REF },
diff --git a/src/gallium/drivers/nv50/nv50_stateobj.h b/src/gallium/drivers/nv50/nv50_stateobj.h
index 4c98c7e..d367a06 100644
--- a/src/gallium/drivers/nv50/nv50_stateobj.h
+++ b/src/gallium/drivers/nv50/nv50_stateobj.h
@@ -21,13 +21,13 @@
 struct nv50_blend_stateobj {
    struct pipe_blend_state pipe;
    int size;
-   uint32_t state[82]; // TODO: allocate less if !independent_blend_enable
+   uint32_t state[84]; // TODO: allocate less if !independent_blend_enable
 };
 
 struct nv50_rasterizer_stateobj {
    struct pipe_rasterizer_state pipe;
    int size;
-   uint32_t state[42];
+   uint32_t state[44];
 };
 
 struct nv50_zsa_stateobj {
diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c
index fb51db8..ebacbb4 100644
--- a/src/gallium/drivers/nv50/nv50_surface.c
+++ b/src/gallium/drivers/nv50/nv50_surface.c
@@ -87,8 +87,8 @@ nv50_2d_texture_set(struct nouveau_channel *chan, int dst,
       return 1;
    }
 
-   width = u_minify(mt->base.base.width0, level);
-   height = u_minify(mt->base.base.height0, level);
+   width = u_minify(mt->base.base.width0, level) << mt->ms_x;
+   height = u_minify(mt->base.base.height0, level) << mt->ms_y;
 
    offset = mt->level[level].offset;
    if (!mt->layout_3d) {
@@ -143,7 +143,13 @@ nv50_2d_texture_do_copy(struct nouveau_channel *chan,
                         unsigned sx, unsigned sy, unsigned sz,
                         unsigned w, unsigned h)
 {
+   static const uint32_t duvdxy[5] =
+   {
+      0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004
+   };
+
    int ret;
+   uint32_t ctrl;
 
    ret = MARK_RING(chan, 2 * 16 + 32, 4);
    if (ret)
@@ -157,24 +163,28 @@ nv50_2d_texture_do_copy(struct nouveau_channel *chan,
    if (ret)
       return ret;
 
-   /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */
+   /* NOTE: 2D engine doesn't work for MS8 */
+   if (src->ms_x)
+      ctrl = 0x11;
+
+   /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */
    BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1);
-   OUT_RING  (chan, 0);
+   OUT_RING  (chan, ctrl);
    BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4);
-   OUT_RING  (chan, dx);
-   OUT_RING  (chan, dy);
-   OUT_RING  (chan, w);
-   OUT_RING  (chan, h);
+   OUT_RING  (chan, dx << dst->ms_x);
+   OUT_RING  (chan, dy << dst->ms_y);
+   OUT_RING  (chan, w << dst->ms_x);
+   OUT_RING  (chan, h << dst->ms_y);
    BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4);
-   OUT_RING  (chan, 0);
-   OUT_RING  (chan, 1);
-   OUT_RING  (chan, 0);
-   OUT_RING  (chan, 1);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f);
    BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4);
    OUT_RING  (chan, 0);
-   OUT_RING  (chan, sx);
+   OUT_RING  (chan, sx << src->ms_x);
    OUT_RING  (chan, 0);
-   OUT_RING  (chan, sy);
+   OUT_RING  (chan, sy << src->ms_y);
 
    return 0;
 }
@@ -197,6 +207,34 @@ nv50_resource_copy_region(struct pipe_context *pipe,
       return;
    }
 
+   nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
+
+   if (src->format == dst->format && src->nr_samples == dst->nr_samples) {
+      struct nv50_m2mf_rect drect, srect;
+      unsigned i;
+      unsigned nx = util_format_get_nblocksx(src->format, src_box->width);
+      unsigned ny = util_format_get_nblocksy(src->format, src_box->height);
+
+      nv50_m2mf_rect_setup(&drect, dst, dst_level, dstx, dsty, dstz);
+      nv50_m2mf_rect_setup(&srect, src, src_level,
+                           src_box->x, src_box->y, src_box->z);
+
+      for (i = 0; i < src_box->depth; ++i) {
+         nv50_m2mf_transfer_rect(&screen->base.base, &drect, &srect, nx, ny);
+
+         if (nv50_miptree(dst)->layout_3d)
+            drect.z++;
+         else
+            drect.base += nv50_miptree(dst)->layer_stride;
+
+         if (nv50_miptree(src)->layout_3d)
+            srect.z++;
+         else
+            srect.base += nv50_miptree(src)->layer_stride;
+      }
+      return;
+   }
+
    assert((src->format == dst->format) ||
           (nv50_2d_format_faithful(src->format) &&
            nv50_2d_format_faithful(dst->format)));
diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c
index 9192d2e..73db9ca 100644
--- a/src/gallium/drivers/nv50/nv50_tex.c
+++ b/src/gallium/drivers/nv50/nv50_tex.c
@@ -159,13 +159,13 @@ nv50_create_sampler_view(struct pipe_context *pipe,
    else
       tic[3] = 0x00300000;
 
-   tic[4] = (1 << 31) | mt->base.base.width0;
+   tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x);
 
-   tic[5] = mt->base.base.height0 & 0xffff;
+   tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff;
    tic[5] |= depth << 16;
    tic[5] |= mt->base.base.last_level << 28;
 
-   tic[6] = 0x03000000;
+   tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */
 
    tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level;
 
diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c
index d9fb22a..0ff79eb 100644
--- a/src/gallium/drivers/nv50/nv50_transfer.c
+++ b/src/gallium/drivers/nv50/nv50_transfer.c
@@ -2,7 +2,6 @@
 #include "util/u_format.h"
 
 #include "nv50_context.h"
-#include "nv50_transfer.h"
 
 #include "nv50_defs.xml.h"
 
@@ -13,7 +12,44 @@ struct nv50_transfer {
    uint32_t nblocksy;
 };
 
-static void
+void
+nv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect,
+                     struct pipe_resource *restrict res, unsigned l,
+                     unsigned x, unsigned y, unsigned z)
+{
+   struct nv50_miptree *mt = nv50_miptree(res);
+   const unsigned w = u_minify(res->width0, l);
+   const unsigned h = u_minify(res->height0, l);
+
+   rect->bo = mt->base.bo;
+   rect->domain = mt->base.domain;
+   rect->base = mt->level[l].offset;
+   rect->pitch = mt->level[l].pitch;
+   if (util_format_is_plain(res->format)) {
+      rect->width = w << mt->ms_x;
+      rect->height = h << mt->ms_y;
+      rect->x = x << mt->ms_x;
+      rect->y = y << mt->ms_y;
+   } else {
+      rect->width = util_format_get_nblocksx(res->format, w);
+      rect->height = util_format_get_nblocksy(res->format, h);
+      rect->x = util_format_get_nblocksx(res->format, x);
+      rect->y = util_format_get_nblocksy(res->format, y);
+   }
+   rect->tile_mode = mt->level[l].tile_mode;
+   rect->cpp = util_format_get_blocksize(res->format);
+
+   if (mt->layout_3d) {
+      rect->z = z;
+      rect->depth = u_minify(res->depth0, l);
+   } else {
+      rect->base += z * mt->layer_stride;
+      rect->z = 0;
+      rect->depth = 1;
+   }
+}
+
+void
 nv50_m2mf_transfer_rect(struct pipe_screen *pscreen,
                         const struct nv50_m2mf_rect *dst,
                         const struct nv50_m2mf_rect *src,
@@ -202,26 +238,14 @@ nv50_miptree_transfer_new(struct pipe_context *pctx,
    struct nv50_context *nv50 = nv50_context(pctx);
    struct pipe_screen *pscreen = pctx->screen;
    struct nouveau_device *dev = nv50->screen->base.device;
-   struct nv50_miptree *mt = nv50_miptree(res);
-   struct nv50_miptree_level *lvl = &mt->level[level];
+   const struct nv50_miptree *mt = nv50_miptree(res);
    struct nv50_transfer *tx;
    uint32_t size;
-   uint32_t w, h, d, z, layer;
    int ret;
 
    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
       return NULL;
 
-   if (mt->layout_3d) {
-      z = box->z;
-      d = u_minify(res->depth0, level);
-      layer = 0;
-   } else {
-      z = 0;
-      d = 1;
-      layer = box->z;
-   }
-
    tx = CALLOC_STRUCT(nv50_transfer);
    if (!tx)
       return NULL;
@@ -232,28 +256,18 @@ nv50_miptree_transfer_new(struct pipe_context *pctx,
    tx->base.usage = usage;
    tx->base.box = *box;
 
-   tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
-   tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
+   if (util_format_is_plain(res->format)) {
+      tx->nblocksx = box->width << mt->ms_x;
+      tx->nblocksy = box->height << mt->ms_x;
+   } else {
+      tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
+      tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
+   }
 
    tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
    tx->base.layer_stride = tx->nblocksy * tx->base.stride;
 
-   w = u_minify(res->width0, level);
-   h = u_minify(res->height0, level);
-
-   tx->rect[0].cpp = tx->rect[1].cpp = util_format_get_blocksize(res->format);
-
-   tx->rect[0].bo = mt->base.bo;
-   tx->rect[0].base = lvl->offset + layer * mt->layer_stride;
-   tx->rect[0].tile_mode = lvl->tile_mode;
-   tx->rect[0].x = util_format_get_nblocksx(res->format, box->x);
-   tx->rect[0].y = util_format_get_nblocksy(res->format, box->y);
-   tx->rect[0].z = z;
-   tx->rect[0].width = util_format_get_nblocksx(res->format, w);
-   tx->rect[0].height = util_format_get_nblocksy(res->format, h);
-   tx->rect[0].depth = d;
-   tx->rect[0].pitch = lvl->pitch;
-   tx->rect[0].domain = NOUVEAU_BO_VRAM;
+   nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
 
    size = tx->base.layer_stride;
 
@@ -264,6 +278,7 @@ nv50_miptree_transfer_new(struct pipe_context *pctx,
       return NULL;
    }
 
+   tx->rect[1].cpp = tx->rect[0].cpp;
    tx->rect[1].width = tx->nblocksx;
    tx->rect[1].height = tx->nblocksy;
    tx->rect[1].depth = 1;
@@ -272,6 +287,7 @@ nv50_miptree_transfer_new(struct pipe_context *pctx,
 
    if (usage & PIPE_TRANSFER_READ) {
       unsigned base = tx->rect[0].base;
+      unsigned z = tx->rect[0].z;
       unsigned i;
       for (i = 0; i < box->depth; ++i) {
          nv50_m2mf_transfer_rect(pscreen, &tx->rect[1], &tx->rect[0],
diff --git a/src/gallium/drivers/nv50/nv50_transfer.h b/src/gallium/drivers/nv50/nv50_transfer.h
index d3259ef..c58cb00 100644
--- a/src/gallium/drivers/nv50/nv50_transfer.h
+++ b/src/gallium/drivers/nv50/nv50_transfer.h
@@ -4,22 +4,6 @@
 
 #include "pipe/p_state.h"
 
-struct pipe_transfer *
-nv50_miptree_transfer_new(struct pipe_context *pcontext,
-                          struct pipe_resource *pt,
-                          unsigned level,
-                          unsigned usage,
-                          const struct pipe_box *box);
-void
-nv50_miptree_transfer_del(struct pipe_context *pcontext,
-                          struct pipe_transfer *ptx);
-void *
-nv50_miptree_transfer_map(struct pipe_context *pcontext,
-                          struct pipe_transfer *ptx);
-void
-nv50_miptree_transfer_unmap(struct pipe_context *pcontext,
-                            struct pipe_transfer *ptx);
-
 struct nv50_m2mf_rect {
    struct nouveau_bo *bo;
    uint32_t base;
@@ -35,4 +19,9 @@ struct nv50_m2mf_rect {
    uint16_t cpp;
 };
 
+void
+nv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect,
+                     struct pipe_resource *restrict res, unsigned l,
+                     unsigned x, unsigned y, unsigned z);
+
 #endif
diff --git a/src/gallium/drivers/nvc0/nvc0_3d.xml.h b/src/gallium/drivers/nvc0/nvc0_3d.xml.h
index 6fba20c..ba7d28b 100644
--- a/src/gallium/drivers/nvc0/nvc0_3d.xml.h
+++ b/src/gallium/drivers/nvc0/nvc0_3d.xml.h
@@ -146,6 +146,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define NVC0_3D_TFB_ENABLE					0x00000744
 
+#define NVC0_3D_SAMPLE_SHADING					0x00000754
+#define NVC0_3D_SAMPLE_SHADING_MIN_SAMPLES__MASK		0x0000000f
+#define NVC0_3D_SAMPLE_SHADING_MIN_SAMPLES__SHIFT		0
+#define NVC0_3D_SAMPLE_SHADING_ENABLE				0x00000010
+
 #define NVC0_3D_LOCAL_BASE					0x0000077c
 
 #define NVC0_3D_LOCAL_ADDRESS_HIGH				0x00000790
diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h
index e592091..bf89164 100644
--- a/src/gallium/drivers/nvc0/nvc0_context.h
+++ b/src/gallium/drivers/nvc0/nvc0_context.h
@@ -19,6 +19,8 @@
 #include "nvc0_program.h"
 #include "nvc0_resource.h"
 
+#include "nv50/nv50_transfer.h"
+
 #include "nouveau/nouveau_context.h"
 
 #include "nvc0_3ddefs.xml.h"
@@ -195,6 +197,11 @@ nvc0_create_sampler_view(struct pipe_context *,
 
 /* nvc0_transfer.c */
 void
+nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen,
+                        const struct nv50_m2mf_rect *dst,
+                        const struct nv50_m2mf_rect *src,
+                        uint32_t nblocksx, uint32_t nblocksy);
+void
 nvc0_m2mf_push_linear(struct nouveau_context *nv,
 		      struct nouveau_bo *dst, unsigned offset, unsigned domain,
 		      unsigned size, void *data);
diff --git a/src/gallium/drivers/nvc0/nvc0_miptree.c b/src/gallium/drivers/nvc0/nvc0_miptree.c
index 8b8e2cf..a72ddf3 100644
--- a/src/gallium/drivers/nvc0/nvc0_miptree.c
+++ b/src/gallium/drivers/nvc0/nvc0_miptree.c
@@ -27,7 +27,6 @@
 
 #include "nvc0_context.h"
 #include "nvc0_resource.h"
-#include "nvc0_transfer.h"
 
 uint32_t
 nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz)
diff --git a/src/gallium/drivers/nvc0/nvc0_resource.h b/src/gallium/drivers/nvc0/nvc0_resource.h
index d699895..6d946c8 100644
--- a/src/gallium/drivers/nvc0/nvc0_resource.h
+++ b/src/gallium/drivers/nvc0/nvc0_resource.h
@@ -42,4 +42,20 @@ nvc0_miptree_surface_new(struct pipe_context *,
 unsigned
 nvc0_mt_zslice_offset(const struct nv50_miptree *, unsigned l, unsigned z);
 
+struct pipe_transfer *
+nvc0_miptree_transfer_new(struct pipe_context *pcontext,
+                          struct pipe_resource *pt,
+                          unsigned level,
+                          unsigned usage,
+                          const struct pipe_box *box);
+void
+nvc0_miptree_transfer_del(struct pipe_context *pcontext,
+                          struct pipe_transfer *ptx);
+void *
+nvc0_miptree_transfer_map(struct pipe_context *pcontext,
+                          struct pipe_transfer *ptx);
+void
+nvc0_miptree_transfer_unmap(struct pipe_context *pcontext,
+                            struct pipe_transfer *ptx);
+
 #endif
diff --git a/src/gallium/drivers/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c
index a2e45b1..605a0b0 100644
--- a/src/gallium/drivers/nvc0/nvc0_screen.c
+++ b/src/gallium/drivers/nvc0/nvc0_screen.c
@@ -37,7 +37,7 @@ nvc0_screen_is_format_supported(struct pipe_screen *pscreen,
                                 unsigned sample_count,
                                 unsigned bindings)
 {
-   if (sample_count > 1)
+   if (sample_count > 2 && sample_count != 4 && sample_count != 8)
       return FALSE;
 
    if (!util_format_is_supported(format, bindings))
diff --git a/src/gallium/drivers/nvc0/nvc0_state.c b/src/gallium/drivers/nvc0/nvc0_state.c
index b0b2065..9f9921c 100644
--- a/src/gallium/drivers/nvc0/nvc0_state.c
+++ b/src/gallium/drivers/nvc0/nvc0_state.c
@@ -88,6 +88,7 @@ nvc0_blend_state_create(struct pipe_context *pipe,
 {
     struct nvc0_blend_stateobj *so = CALLOC_STRUCT(nvc0_blend_stateobj);
     int i;
+    uint32_t ms;
 
     so->pipe = *cso;
 
@@ -144,6 +145,15 @@ nvc0_blend_state_create(struct pipe_context *pipe,
             SB_DATA(so, nvc0_colormask(cso->rt[i].colormask));
     }
 
+    ms = 0;
+    if (cso->alpha_to_coverage)
+       ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE;
+    if (cso->alpha_to_one)
+       ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE;
+
+    SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1);
+    SB_DATA    (so, ms);
+
     assert(so->size <= (sizeof(so->state) / sizeof(so->state[0])));
     return so;
 }
@@ -190,6 +200,8 @@ nvc0_rasterizer_state_create(struct pipe_context *pipe,
     SB_BEGIN_3D(so, FRAG_COLOR_CLAMP_EN, 1);
     SB_DATA    (so, cso->clamp_fragment_color ? 0x11111111 : 0x00000000);
 
+    SB_IMMED_3D(so, MULTISAMPLE_ENABLE, cso->multisample);
+
     SB_IMMED_3D(so, LINE_SMOOTH_ENABLE, cso->line_smooth);
     if (cso->line_smooth)
        SB_BEGIN_3D(so, LINE_WIDTH_SMOOTH, 1);
diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c
index bd40a23..968d7a7 100644
--- a/src/gallium/drivers/nvc0/nvc0_state_validate.c
+++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c
@@ -59,6 +59,7 @@ nvc0_validate_fb(struct nvc0_context *nvc0)
     struct nouveau_channel *chan = nvc0->screen->base.channel;
     struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
     unsigned i;
+    unsigned ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
     boolean serialize = FALSE;
 
     nvc0_bufctx_reset(nvc0, NVC0_BUFCTX_FRAME);
@@ -89,6 +90,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0)
         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)
            serialize = TRUE;
         mt->base.status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
@@ -123,6 +126,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0)
         BEGIN_RING(chan, RING_3D(ZETA_BASE_LAYER), 1);
         OUT_RING  (chan, sf->base.u.tex.first_layer);
 
+        ms_mode = mt->ms_mode;
+
         if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
            serialize = TRUE;
         mt->base.status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
@@ -135,6 +140,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0)
         OUT_RING  (chan, 0);
     }
 
+    IMMED_RING(chan, RING_3D(MULTISAMPLE_MODE), ms_mode);
+
     if (serialize) {
        BEGIN_RING(chan, RING_3D(SERIALIZE), 1);
        OUT_RING  (chan, 0);
@@ -390,6 +397,28 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0)
 }
 
 static void
+nvc0_validate_sample_mask(struct nvc0_context *nvc0)
+{
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
+
+   unsigned mask[4] =
+   {
+      nvc0->sample_mask & 0xffff,
+      nvc0->sample_mask & 0xffff,
+      nvc0->sample_mask & 0xffff,
+      nvc0->sample_mask & 0xffff
+   };
+
+   BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4);
+   OUT_RING  (chan, mask[0]);
+   OUT_RING  (chan, mask[1]);
+   OUT_RING  (chan, mask[2]);
+   OUT_RING  (chan, mask[3]);
+   BEGIN_RING(chan, RING_3D(SAMPLE_SHADING), 1);
+   OUT_RING  (chan, 0x01);
+}
+
+static void
 nvc0_validate_derived_1(struct nvc0_context *nvc0)
 {
    struct nouveau_channel *chan = nvc0->screen->base.channel;
@@ -438,6 +467,7 @@ static struct state_validate {
     { nvc0_validate_fb,            NVC0_NEW_FRAMEBUFFER },
     { nvc0_validate_blend,         NVC0_NEW_BLEND },
     { nvc0_validate_zsa,           NVC0_NEW_ZSA },
+    { nvc0_validate_sample_mask,   NVC0_NEW_SAMPLE_MASK },
     { nvc0_validate_rasterizer,    NVC0_NEW_RASTERIZER },
     { nvc0_validate_blend_colour,  NVC0_NEW_BLEND_COLOUR },
     { nvc0_validate_stencil_ref,   NVC0_NEW_STENCIL_REF },
diff --git a/src/gallium/drivers/nvc0/nvc0_stateobj.h b/src/gallium/drivers/nvc0/nvc0_stateobj.h
index e0fe9df..0686c52 100644
--- a/src/gallium/drivers/nvc0/nvc0_stateobj.h
+++ b/src/gallium/drivers/nvc0/nvc0_stateobj.h
@@ -19,13 +19,13 @@
 struct nvc0_blend_stateobj {
    struct pipe_blend_state pipe;
    int size;
-   uint32_t state[70];
+   uint32_t state[72];
 };
 
 struct nvc0_rasterizer_stateobj {
    struct pipe_rasterizer_state pipe;
    int size;
-   uint32_t state[38];
+   uint32_t state[39];
 };
 
 struct nvc0_zsa_stateobj {
diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c
index e1e4c30..4484a9f 100644
--- a/src/gallium/drivers/nvc0/nvc0_surface.c
+++ b/src/gallium/drivers/nvc0/nvc0_surface.c
@@ -31,7 +31,6 @@
 
 #include "nvc0_context.h"
 #include "nvc0_resource.h"
-#include "nvc0_transfer.h"
 
 #include "nv50/nv50_defs.xml.h"
 
@@ -91,8 +90,8 @@ nvc0_2d_texture_set(struct nouveau_channel *chan, int dst,
       return 1;
    }
 
-   width = u_minify(mt->base.base.width0, level);
-   height = u_minify(mt->base.base.height0, level);
+   width = u_minify(mt->base.base.width0, level) << mt->ms_x;
+   height = u_minify(mt->base.base.height0, level) << mt->ms_y;
    depth = u_minify(mt->base.base.depth0, level);
 
    /* layer has to be < depth, and depth > tile depth / 2 */
@@ -151,7 +150,13 @@ nvc0_2d_texture_do_copy(struct nouveau_channel *chan,
                         unsigned sx, unsigned sy, unsigned sz,
                         unsigned w, unsigned h)
 {
+   static const uint32_t duvdxy[5] =
+   {
+      0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004
+   };
+
    int ret;
+   uint32_t ctrl = 0x00;
 
    ret = MARK_RING(chan, 2 * 16 + 32, 4);
    if (ret)
@@ -165,66 +170,33 @@ nvc0_2d_texture_do_copy(struct nouveau_channel *chan,
    if (ret)
       return ret;
 
-   /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */
+   /* NOTE: 2D engine doesn't work for MS8 */
+   if (src->ms_x)
+      ctrl = 0x11;
+
+   /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */
    BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1);
-   OUT_RING  (chan, 0);
+   OUT_RING  (chan, ctrl);
    BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4);
-   OUT_RING  (chan, dx);
-   OUT_RING  (chan, dy);
-   OUT_RING  (chan, w);
-   OUT_RING  (chan, h);
+   OUT_RING  (chan, dx << dst->ms_x);
+   OUT_RING  (chan, dy << dst->ms_y);
+   OUT_RING  (chan, w << dst->ms_x);
+   OUT_RING  (chan, h << dst->ms_y);
    BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4);
-   OUT_RING  (chan, 0);
-   OUT_RING  (chan, 1);
-   OUT_RING  (chan, 0);
-   OUT_RING  (chan, 1);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000);
+   OUT_RING  (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f);
    BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4);
    OUT_RING  (chan, 0);
-   OUT_RING  (chan, sx);
+   OUT_RING  (chan, sx << src->ms_x);
    OUT_RING  (chan, 0);
-   OUT_RING  (chan, sy);
+   OUT_RING  (chan, sy << src->ms_x);
 
    return 0;
 }
 
 static void
-nvc0_setup_m2mf_rect(struct nvc0_m2mf_rect *rect,
-                     struct pipe_resource *restrict res, unsigned l,
-                     unsigned x, unsigned y, unsigned z)
-{
-   struct nv50_miptree *mt = nv50_miptree(res);
-   const unsigned w = u_minify(res->width0, l);
-   const unsigned h = u_minify(res->height0, l);
-
-   rect->bo = mt->base.bo;
-   rect->domain = mt->base.domain;
-   rect->base = mt->level[l].offset;
-   rect->pitch = mt->level[l].pitch;
-   if (util_format_is_plain(res->format)) {
-      rect->width = w;
-      rect->height = h;
-      rect->x = x;
-      rect->y = y;
-   } else {
-      rect->width = util_format_get_nblocksx(res->format, w);
-      rect->height = util_format_get_nblocksy(res->format, h);
-      rect->x = util_format_get_nblocksx(res->format, x);
-      rect->y = util_format_get_nblocksy(res->format, y);
-   }
-   rect->tile_mode = mt->level[l].tile_mode;
-   rect->cpp = util_format_get_blocksize(res->format);
-
-   if (mt->layout_3d) {
-      rect->z = z;
-      rect->depth = u_minify(res->depth0, l);
-   } else {
-      rect->base += z * mt->layer_stride;
-      rect->z = 0;
-      rect->depth = 1;
-   }
-}
-
-static void
 nvc0_resource_copy_region(struct pipe_context *pipe,
                           struct pipe_resource *dst, unsigned dst_level,
                           unsigned dstx, unsigned dsty, unsigned dstz,
@@ -244,14 +216,14 @@ nvc0_resource_copy_region(struct pipe_context *pipe,
 
    nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
 
-   if (src->format == dst->format) {
-      struct nvc0_m2mf_rect drect, srect;
+   if (src->format == dst->format && src->nr_samples == dst->nr_samples) {
+      struct nv50_m2mf_rect drect, srect;
       unsigned i;
       unsigned nx = util_format_get_nblocksx(src->format, src_box->width);
       unsigned ny = util_format_get_nblocksy(src->format, src_box->height);
 
-      nvc0_setup_m2mf_rect(&drect, dst, dst_level, dstx, dsty, dstz);
-      nvc0_setup_m2mf_rect(&srect, src, src_level,
+      nv50_m2mf_rect_setup(&drect, dst, dst_level, dstx, dsty, dstz);
+      nv50_m2mf_rect_setup(&srect, src, src_level,
                            src_box->x, src_box->y, src_box->z);
 
       for (i = 0; i < src_box->depth; ++i) {
diff --git a/src/gallium/drivers/nvc0/nvc0_tex.c b/src/gallium/drivers/nvc0/nvc0_tex.c
index 4b82fdf..0cbb4b3 100644
--- a/src/gallium/drivers/nvc0/nvc0_tex.c
+++ b/src/gallium/drivers/nvc0/nvc0_tex.c
@@ -114,6 +114,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    depth = MAX2(mt->base.base.array_size, mt->base.base.depth0);
 
    if (mt->base.base.target == PIPE_TEXTURE_1D_ARRAY ||
+   /*  mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS || */
        mt->base.base.target == PIPE_TEXTURE_2D_ARRAY) {
       /* there doesn't seem to be a base layer field in TIC */
       tic[1] = view->pipe.u.tex.first_layer * mt->layer_stride;
@@ -124,6 +125,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    case PIPE_TEXTURE_1D:
       tic[2] |= NV50_TIC_2_TARGET_1D;
       break;
+/* case PIPE_TEXTURE_2D_MS: */
    case PIPE_TEXTURE_2D:
       tic[2] |= NV50_TIC_2_TARGET_2D;
       break;
@@ -143,6 +145,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    case PIPE_TEXTURE_1D_ARRAY:
       tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY;
       break;
+/* case PIPE_TEXTURE_2D_ARRAY_MS: */
    case PIPE_TEXTURE_2D_ARRAY:
       tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY;
       break;
@@ -159,16 +162,22 @@ nvc0_create_sampler_view(struct pipe_context *pipe,
    else
       tic[3] = 0x00300000;
 
-   tic[4] = (1 << 31) | mt->base.base.width0;
+   tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x);
 
-   tic[5] = mt->base.base.height0 & 0xffff;
+   tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff;
    tic[5] |= depth << 16;
    tic[5] |= mt->base.base.last_level << 28;
 
-   tic[6] = 0x03000000;
+   tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */
 
    tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level;
 
+   /*
+   if (mt->base.base.target == PIPE_TEXTURE_2D_MS ||
+       mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS)
+      tic[7] |= mt->ms_mode << 12;
+   */
+
    return &view->pipe;
 }
 
diff --git a/src/gallium/drivers/nvc0/nvc0_transfer.c b/src/gallium/drivers/nvc0/nvc0_transfer.c
index 1170f12..ecc9e21 100644
--- a/src/gallium/drivers/nvc0/nvc0_transfer.c
+++ b/src/gallium/drivers/nvc0/nvc0_transfer.c
@@ -2,13 +2,12 @@
 #include "util/u_format.h"
 
 #include "nvc0_context.h"
-#include "nvc0_transfer.h"
 
 #include "nv50/nv50_defs.xml.h"
 
 struct nvc0_transfer {
    struct pipe_transfer base;
-   struct nvc0_m2mf_rect rect[2];
+   struct nv50_m2mf_rect rect[2];
    uint32_t nblocksx;
    uint16_t nblocksy;
    uint16_t nlayers;
@@ -16,8 +15,8 @@ struct nvc0_transfer {
 
 void
 nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen,
-                        const struct nvc0_m2mf_rect *dst,
-                        const struct nvc0_m2mf_rect *src,
+                        const struct nv50_m2mf_rect *dst,
+                        const struct nv50_m2mf_rect *src,
                         uint32_t nblocksx, uint32_t nblocksy)
 {
    struct nouveau_channel *chan = nouveau_screen(pscreen)->channel;
@@ -174,9 +173,10 @@ nvc0_m2mf_copy_linear(struct nouveau_context *nv,
    }
 }
 
+#if 0
 static void
 nvc0_m2mf_push_rect(struct pipe_screen *pscreen,
-                    const struct nvc0_m2mf_rect *dst,
+                    const struct nv50_m2mf_rect *dst,
                     const void *data,
                     unsigned nblocksx, unsigned nblocksy)
 {
@@ -228,6 +228,7 @@ nvc0_m2mf_push_rect(struct pipe_screen *pscreen,
       nblocksy -= line_count;
    }
 }
+#endif
 
 struct pipe_transfer *
 nvc0_miptree_transfer_new(struct pipe_context *pctx,
@@ -240,10 +241,8 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx,
    struct pipe_screen *pscreen = pctx->screen;
    struct nouveau_device *dev = nvc0->screen->base.device;
    struct nv50_miptree *mt = nv50_miptree(res);
-   struct nv50_miptree_level *lvl = &mt->level[level];
    struct nvc0_transfer *tx;
    uint32_t size;
-   uint32_t w, h, d, z, layer;
    int ret;
 
    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
@@ -253,45 +252,25 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx,
    if (!tx)
       return NULL;
 
-   if (mt->layout_3d) {
-      z = box->z;
-      d = u_minify(res->depth0, level);
-      layer = 0;
-   } else {
-      z = 0;
-      d = 1;
-      layer = box->z;
-   }
-   tx->nlayers = box->depth;
-
    pipe_resource_reference(&tx->base.resource, res);
 
    tx->base.level = level;
    tx->base.usage = usage;
    tx->base.box = *box;
 
-   tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
-   tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
+   if (util_format_is_plain(res->format)) {
+      tx->nblocksx = box->width << mt->ms_x;
+      tx->nblocksy = box->height << mt->ms_y;
+   } else {
+      tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
+      tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
+   }
+   tx->nlayers = box->depth;
 
    tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
    tx->base.layer_stride = tx->nblocksy * tx->base.stride;
 
-   w = u_minify(res->width0, level);
-   h = u_minify(res->height0, level);
-
-   tx->rect[0].cpp = tx->rect[1].cpp = util_format_get_blocksize(res->format);
-
-   tx->rect[0].bo = mt->base.bo;
-   tx->rect[0].base = lvl->offset + layer * mt->layer_stride;
-   tx->rect[0].tile_mode = lvl->tile_mode;
-   tx->rect[0].x = util_format_get_nblocksx(res->format, box->x);
-   tx->rect[0].y = util_format_get_nblocksy(res->format, box->y);
-   tx->rect[0].z = z;
-   tx->rect[0].width = util_format_get_nblocksx(res->format, w);
-   tx->rect[0].height = util_format_get_nblocksy(res->format, h);
-   tx->rect[0].depth = d;
-   tx->rect[0].pitch = lvl->pitch;
-   tx->rect[0].domain = NOUVEAU_BO_VRAM;
+   nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
 
    size = tx->base.layer_stride;
 
@@ -302,6 +281,7 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx,
       return NULL;
    }
 
+   tx->rect[1].cpp = tx->rect[0].cpp;
    tx->rect[1].width = tx->nblocksx;
    tx->rect[1].height = tx->nblocksy;
    tx->rect[1].depth = 1;
@@ -310,6 +290,7 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx,
 
    if (usage & PIPE_TRANSFER_READ) {
       unsigned base = tx->rect[0].base;
+      unsigned z = tx->rect[0].z;
       unsigned i;
       for (i = 0; i < tx->nlayers; ++i) {
          nvc0_m2mf_transfer_rect(pscreen, &tx->rect[1], &tx->rect[0],
diff --git a/src/gallium/drivers/nvc0/nvc0_transfer.h b/src/gallium/drivers/nvc0/nvc0_transfer.h
deleted file mode 100644
index 803ee34..0000000
--- a/src/gallium/drivers/nvc0/nvc0_transfer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-
-#ifndef __NVC0_TRANSFER_H__
-#define __NVC0_TRANSFER_H__
-
-#include "pipe/p_state.h"
-
-struct pipe_transfer *
-nvc0_miptree_transfer_new(struct pipe_context *pcontext,
-                          struct pipe_resource *pt,
-                          unsigned level,
-                          unsigned usage,
-                          const struct pipe_box *box);
-void
-nvc0_miptree_transfer_del(struct pipe_context *pcontext,
-                          struct pipe_transfer *ptx);
-void *
-nvc0_miptree_transfer_map(struct pipe_context *pcontext,
-                          struct pipe_transfer *ptx);
-void
-nvc0_miptree_transfer_unmap(struct pipe_context *pcontext,
-                            struct pipe_transfer *ptx);
-
-struct nvc0_m2mf_rect {
-   struct nouveau_bo *bo;
-   uint32_t base;
-   unsigned domain;
-   uint32_t pitch;
-   uint32_t width;
-   uint32_t x;
-   uint32_t height;
-   uint32_t y;
-   uint16_t depth;
-   uint16_t z;
-   uint16_t tile_mode;
-   uint16_t cpp;
-};
-
-void
-nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen,
-                        const struct nvc0_m2mf_rect *dst,
-                        const struct nvc0_m2mf_rect *src,
-                        uint32_t nblocksx, uint32_t nblocksy);
-
-#endif




More information about the mesa-commit mailing list