diff options
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c | 205 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h | 6 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c | 1 |
3 files changed, 173 insertions, 39 deletions
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c index a86b7265440..09e66d1bdcd 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c @@ -23,41 +23,69 @@ #include <stdint.h> #include <stdlib.h> #include <errno.h> +#include <assert.h> #include "nouveau_drmif.h" #include "nouveau_dma.h" #include "nouveau_local.h" -int -nouveau_bo_init(struct nouveau_device *dev) +static void +nouveau_mem_free(struct nouveau_device *dev, struct drm_nouveau_mem_alloc *ma, + void **map) { - return 0; + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct drm_nouveau_mem_free mf; + + if (map && *map) { + drmUnmap(*map, ma->size); + *map = NULL; + } + + if (ma->size) { + mf.offset = ma->offset; + mf.flags = ma->flags; + drmCommandWrite(nvdev->fd, DRM_NOUVEAU_MEM_FREE, + &mf, sizeof(mf)); + ma->size = 0; + } } -void -nouveau_bo_takedown(struct nouveau_device *dev) +static int +nouveau_mem_alloc(struct nouveau_device *dev, unsigned size, unsigned align, + uint32_t flags, struct drm_nouveau_mem_alloc *ma, void **map) { + struct nouveau_device_priv *nvdev = nouveau_device(dev); + int ret; + + ma->alignment = align; + ma->size = size; + ma->flags = flags; + if (map) + ma->flags |= NOUVEAU_MEM_MAPPED; + ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_MEM_ALLOC, ma, + sizeof(struct drm_nouveau_mem_alloc)); + if (ret) + return ret; + + if (map) { + ret = drmMap(nvdev->fd, ma->map_handle, ma->size, map); + if (ret) { + *map = NULL; + nouveau_mem_free(dev, ma, map); + return ret; + } + } + + return 0; } static int nouveau_bo_realloc_gpu(struct nouveau_bo_priv *nvbo, uint32_t flags, int size) { - struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); int ret; if (nvbo->drm.size && nvbo->drm.size != size) { - struct drm_nouveau_mem_free f; - - if (nvbo->map) { - drmUnmap(nvbo->map, nvbo->drm.size); - nvbo->map = NULL; - } - - f.flags = nvbo->drm.flags; - f.offset = nvbo->drm.offset; - drmCommandWrite(nvdev->fd, DRM_NOUVEAU_MEM_FREE, &f, sizeof(f)); - - nvbo->drm.size = 0; + nouveau_mem_free(nvbo->base.device, &nvbo->drm, &nvbo->map); } if (size && !nvbo->drm.size) { @@ -71,27 +99,76 @@ nouveau_bo_realloc_gpu(struct nouveau_bo_priv *nvbo, uint32_t flags, int size) nvbo->drm.flags |= NOUVEAU_MEM_MAPPED; } - nvbo->drm.size = size; - - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_MEM_ALLOC, - &nvbo->drm, sizeof(nvbo->drm)); + ret = nouveau_mem_alloc(nvbo->base.device, size, + nvbo->drm.alignment, nvbo->drm.flags, + &nvbo->drm, &nvbo->map); if (ret) { - free(nvbo); - return ret; + assert(0); } + } - ret = drmMap(nvdev->fd, nvbo->drm.map_handle, nvbo->drm.size, - &nvbo->map); - if (ret) { - nvbo->map = NULL; - nouveau_bo_del((void *)&nvbo); - return ret; - } + return 0; +} + +static void +nouveau_bo_tmp_del(void *priv) +{ + struct nouveau_resource *r = priv; + + nouveau_fence_del((struct nouveau_fence **)&r->priv); + nouveau_resource_free(&r); +} + +static struct nouveau_resource * +nouveau_bo_tmp(struct nouveau_channel *chan, unsigned size, + struct nouveau_fence *fence) +{ + struct nouveau_device_priv *nvdev = nouveau_device(chan->device); + struct nouveau_resource *r = NULL; + struct nouveau_fence *ref = NULL; + + if (fence) + nouveau_fence_ref(fence, &ref); + else + nouveau_fence_new(chan, &ref); + assert(ref); + + while (nouveau_resource_alloc(nvdev->sa_heap, size, ref, &r)) { + nouveau_fence_flush(chan); + } + nouveau_fence_signal_cb(ref, nouveau_bo_tmp_del, r); + + return r; +} + +int +nouveau_bo_init(struct nouveau_device *dev) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + int ret; + + ret = nouveau_mem_alloc(dev, 128*1024, 0, NOUVEAU_MEM_AGP | + NOUVEAU_MEM_PCI, &nvdev->sa, &nvdev->sa_map); + if (ret) + return ret; + + ret = nouveau_resource_init(&nvdev->sa_heap, 0, nvdev->sa.size); + if (ret) { + nouveau_mem_free(dev, &nvdev->sa, &nvdev->sa_map); + return ret; } return 0; } +void +nouveau_bo_takedown(struct nouveau_device *dev) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + + nouveau_mem_free(dev, &nvdev->sa, &nvdev->sa_map); +} + int nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align, int size, struct nouveau_bo **bo) @@ -247,9 +324,36 @@ nouveau_bo_upload(struct nouveau_bo_priv *nvbo) return 0; } -int -nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo, - struct nouveau_fence *fence, uint32_t flags) +static int +nouveau_bo_validate_user(struct nouveau_channel *chan, struct nouveau_bo *bo, + struct nouveau_fence *fence, uint32_t flags) +{ + struct nouveau_channel_priv *nvchan = nouveau_channel(chan); + struct nouveau_device_priv *nvdev = nouveau_device(chan->device); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + struct nouveau_resource *r; + + if (nvchan->user_charge + bo->size > nvdev->sa.size) + return 1; + nvchan->user_charge += bo->size; + + if (!(flags & NOUVEAU_BO_GART)) + return 1; + + r = nouveau_bo_tmp(chan, bo->size, fence); + if (!r) + return 1; + + memcpy(nvdev->sa_map + r->start, nvbo->sysmem, bo->size); + + nvbo->base.offset = nvdev->sa.offset + r->start; + nvbo->base.flags = NOUVEAU_BO_GART; + return 0; +} + +static int +nouveau_bo_validate_bo(struct nouveau_channel *chan, struct nouveau_bo *bo, + struct nouveau_fence *fence, uint32_t flags) { struct nouveau_bo_priv *nvbo = nouveau_bo(bo); @@ -264,13 +368,9 @@ nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo, if (nvbo->user) { nouveau_bo_upload(nvbo); } - - if (nvbo->fence) - nouveau_fence_del(&nvbo->fence); - nouveau_fence_ref(fence, &nvbo->fence); nvbo->base.offset = nvbo->drm.offset; - if (nvbo->drm.flags & NOUVEAU_MEM_AGP) + if (nvbo->drm.flags & (NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI)) nvbo->base.flags = NOUVEAU_BO_GART; else nvbo->base.flags = NOUVEAU_BO_VRAM; @@ -278,3 +378,30 @@ nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo, return 0; } +int +nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo, + struct nouveau_fence *fence, uint32_t flags) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + int ret; + + if (nvbo->user) { + ret = nouveau_bo_validate_user(chan, bo, fence, flags); + if (ret) { + ret = nouveau_bo_validate_bo(chan, bo, fence, flags); + if (ret) + return ret; + } + } else { + ret = nouveau_bo_validate_bo(chan, bo, fence, flags); + if (ret) + return ret; + } + + if (nvbo->fence) + nouveau_fence_del(&nvbo->fence); + nouveau_fence_ref(fence, &nvbo->fence); + + return 0; +} + diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h index 4dc40b7593d..11a15d632ce 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h @@ -42,6 +42,10 @@ struct nouveau_device_priv { drm_context_t ctx; drmLock *lock; int needs_close; + + struct drm_nouveau_mem_alloc sa; + void *sa_map; + struct nouveau_resource *sa_heap; }; #define nouveau_device(n) ((struct nouveau_device_priv *)(n)) @@ -180,6 +184,8 @@ struct nouveau_channel_priv { struct nouveau_resource *pb_heap; struct nouveau_pushbuf *pb_head; struct nouveau_pushbuf *pb_tail; + + unsigned user_charge; }; #define nouveau_channel(n) ((struct nouveau_channel_priv *)(n)) diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c index 2179664838e..11754417893 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c @@ -105,6 +105,7 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan) return ret; /* Validate buffers + apply relocations */ + nvchan->user_charge = 0; while ((pbbo = ptr_to_pbbo(nvpb->buffers))) { struct nouveau_pushbuf_reloc *r; struct nouveau_bo *bo = &ptr_to_bo(pbbo->handle)->base; |