diff options
Diffstat (limited to 'src/gallium/winsys/g3dvl')
-rw-r--r-- | src/gallium/winsys/g3dvl/nouveau/nouveau_winsys_pipe.c | 64 |
1 files changed, 46 insertions, 18 deletions
diff --git a/src/gallium/winsys/g3dvl/nouveau/nouveau_winsys_pipe.c b/src/gallium/winsys/g3dvl/nouveau/nouveau_winsys_pipe.c index d841eb4a04..17c409e1ce 100644 --- a/src/gallium/winsys/g3dvl/nouveau/nouveau_winsys_pipe.c +++ b/src/gallium/winsys/g3dvl/nouveau/nouveau_winsys_pipe.c @@ -89,25 +89,10 @@ nouveau_surface_release(struct pipe_winsys *ws, struct pipe_surface **s) } } -static struct pipe_buffer * -nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment, - unsigned usage, unsigned size) +static uint32_t +nouveau_flags_from_usage(struct nouveau_context *nv, unsigned usage) { - struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws; - struct nouveau_context *nv = nvpws->nv; - struct nouveau_device *dev = nv->nv_screen->device; - struct nouveau_pipe_buffer *nvbuf; - uint32_t flags; - - nvbuf = calloc(1, sizeof(*nvbuf)); - if (!nvbuf) - return NULL; - nvbuf->base.refcount = 1; - nvbuf->base.alignment = alignment; - nvbuf->base.usage = usage; - nvbuf->base.size = size; - - flags = NOUVEAU_BO_LOCAL; + uint32_t flags = NOUVEAU_BO_LOCAL; if (usage & PIPE_BUFFER_USAGE_PIXEL) { if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE) @@ -126,6 +111,29 @@ nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment, flags |= NOUVEAU_BO_GART; } + return flags; +} + +static struct pipe_buffer * +nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment, + unsigned usage, unsigned size) +{ + struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws; + struct nouveau_context *nv = nvpws->nv; + struct nouveau_device *dev = nv->nv_screen->device; + struct nouveau_pipe_buffer *nvbuf; + uint32_t flags; + + nvbuf = calloc(1, sizeof(*nvbuf)); + if (!nvbuf) + return NULL; + nvbuf->base.refcount = 1; + nvbuf->base.alignment = alignment; + nvbuf->base.usage = usage; + nvbuf->base.size = size; + + flags = nouveau_flags_from_usage(nv, usage); + if (nouveau_bo_new(dev, flags, alignment, size, &nvbuf->bo)) { free(nvbuf); return NULL; @@ -176,6 +184,26 @@ nouveau_pipe_bo_map(struct pipe_winsys *pws, struct pipe_buffer *buf, if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) map_flags |= NOUVEAU_BO_WR; + if ((map_flags & NOUVEAU_BO_RDWR) == NOUVEAU_BO_WR && + !nouveau_bo_busy(nvbuf->bo, map_flags)) { + /* XXX: Technically incorrect. If the client maps a buffer for write-only + * and leaves part of the buffer untouched it probably expects those parts + * to remain intact. This is violated because we allocate a whole new buffer + * and don't copy the previous buffer's contents, so this optimization is + * only valid if the client intends to overwrite the whole buffer. + */ + struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws; + struct nouveau_context *nv = nvpws->nv; + struct nouveau_device *dev = nv->nv_screen->device; + struct nouveau_bo *rename; + uint32_t flags = nouveau_flags_from_usage(nv, buf->usage); + + if (!nouveau_bo_new(dev, flags, buf->alignment, buf->size, &rename)) { + nouveau_bo_del(&nvbuf->bo); + nvbuf->bo = rename; + } + } + if (nouveau_bo_map(nvbuf->bo, map_flags)) return NULL; return nvbuf->bo->map; |