nouveau: m2mf fallback path for region copies.
authorBen Skeggs <skeggsb@gmail.com>
Sun, 18 Nov 2007 12:08:33 +0000 (23:08 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Sun, 18 Nov 2007 12:08:33 +0000 (23:08 +1100)
src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
src/mesa/drivers/dri/nouveau_winsys/nv04_region.c

index cd04b08eca1f4defef65927252c25af8f30bc975..f2557af935dd08d1cb92cad5e1d5b9605898d169 100644 (file)
@@ -52,6 +52,7 @@ struct nouveau_context {
        struct nouveau_grobj    *NvCtxSurf2D;
        struct nouveau_grobj    *NvImageBlit;
        struct nouveau_grobj    *NvGdiRect;
+       struct nouveau_grobj    *NvM2MF;
        uint32_t                 next_handle;
        uint32_t                 next_sequence;
 
index cbe70983f5cb4f4d7ff0346f8572d8371fd40233..f41e45c73a63625126c03365607f52fc5df35634 100644 (file)
@@ -33,6 +33,40 @@ nv04_region_display(void)
        return 0;
 }
 
+static int
+nv04_region_copy_m2mf(struct nouveau_context *nv, struct pipe_region *dst,
+                     unsigned dst_offset, struct pipe_region *src,
+                     unsigned src_offset, unsigned line_len, unsigned height)
+{
+       BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+       OUT_RELOCo(src->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+                  NOUVEAU_BO_RD);
+       OUT_RELOCo(dst->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+                  NOUVEAU_BO_WR);
+
+       while (height) {
+               int count = (height > 2047) ? 2047 : height;
+
+               BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+               OUT_RELOCl(src->buffer, src_offset, NOUVEAU_BO_VRAM |
+                          NOUVEAU_BO_GART | NOUVEAU_BO_RD);
+               OUT_RELOCl(dst->buffer, dst_offset, NOUVEAU_BO_VRAM |
+                          NOUVEAU_BO_GART | NOUVEAU_BO_WR);
+               OUT_RING  (src->pitch * src->cpp);
+               OUT_RING  (dst->pitch * dst->cpp);
+               OUT_RING  (line_len);
+               OUT_RING  (count);
+               OUT_RING  (0x0101);
+               OUT_RING  (0);
+
+               height -= count;
+               src_offset += src->pitch * count;
+               dst_offset += dst->pitch * count;
+       }
+
+       return 0;
+}
+
 static int
 nv04_region_copy(struct nouveau_context *nv, struct pipe_region *dst,
                 unsigned dst_offset, unsigned dx, unsigned dy,
@@ -44,6 +78,19 @@ nv04_region_copy(struct nouveau_context *nv, struct pipe_region *dst,
        if (src->cpp != dst->cpp)
                return 1;
 
+       NOUVEAU_ERR("preg\n");
+
+       /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
+        * to NV_MEMORY_TO_MEMORY_FORMAT in this case.
+        */
+       if ((src_offset & 63) || (dst_offset & 63)) {
+               dst_offset += (dy * dst->pitch + dx) * dst->cpp;
+               src_offset += (sy * src->pitch + sx) * src->cpp;
+               return nv04_region_copy_m2mf(nv, dst, dst_offset, src,
+                                            src_offset, w * src->cpp, h);
+
+       }
+
        if ((format = nv04_surface_format(dst->cpp)) < 0) {
                NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
                return 1;
@@ -119,6 +166,14 @@ nouveau_region_init_nv04(struct nouveau_context *nv)
 {
        int ret;
 
+       if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x39,
+                                      &nv->NvM2MF))) {
+               NOUVEAU_ERR("Error creating m2mf object: %d\n", ret);
+               return 1;
+       }
+       BEGIN_RING(NvM2MF, 0x0180, 1);
+       OUT_RING  (nv->sync_notifier->handle);
+
        if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x62,
                                       &nv->NvCtxSurf2D))) {
                NOUVEAU_ERR("Error creating 2D surface object: %d\n", ret);