From b560ed2444383b9634786fe742b8cb6f5cdfc781 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 2 Mar 2008 14:56:42 +1100 Subject: nouveau: enable multi-context/single-channel support for nv40 --- src/gallium/winsys/dri/nouveau/nouveau_context.c | 63 +++++++++++++++++++++--- src/gallium/winsys/dri/nouveau/nouveau_context.h | 8 +++ src/gallium/winsys/dri/nouveau/nouveau_screen.h | 2 + src/gallium/winsys/dri/nouveau/nouveau_winsys.c | 10 ++-- 4 files changed, 74 insertions(+), 9 deletions(-) (limited to 'src/gallium/winsys/dri/nouveau') diff --git a/src/gallium/winsys/dri/nouveau/nouveau_context.c b/src/gallium/winsys/dri/nouveau/nouveau_context.c index 7915afae22..dc852c9f49 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_context.c +++ b/src/gallium/winsys/dri/nouveau/nouveau_context.c @@ -4,6 +4,7 @@ #include "utils.h" #include "state_tracker/st_public.h" +#include "state_tracker/st_context.h" #include "pipe/p_defines.h" #include "pipe/p_context.h" @@ -101,7 +102,8 @@ nouveau_context_create(const __GLcontextModes *glVis, struct nouveau_device_priv *nvdev; struct pipe_context *pipe = NULL; struct st_context *st_share = NULL; - int ret; + struct nouveau_channel_context *nvc = NULL; + int i, ret; if (sharedContextPrivate) { st_share = ((struct nouveau_context *)sharedContextPrivate)->st; @@ -163,12 +165,56 @@ nouveau_context_create(const __GLcontextModes *glVis, nv->frontbuffer = fb_surf; } - nv->nvc = nouveau_channel_context_create(&nvdev->base, nv->chipset); - if (!nv->nvc) { - NOUVEAU_ERR("Failed initialising GPU channel context\n"); - return GL_FALSE; + /* Attempt to share a single channel between multiple contexts from + * a single process. + */ + nvc = nv_screen->nvc; + if (!nvc && st_share) { + struct nouveau_context *snv = st_share->pipe->priv; + if (snv) { + nvc = snv->nvc; + } + } + + /*XXX: temporary - disable multi-context/single-channel on non-NV4x */ + switch (nv->chipset & 0xf0) { + case 0x40: + case 0x60: + break; + default: + nvc = NULL; + break; + } + + if (!nvc) { + nvc = nouveau_channel_context_create(&nvdev->base, nv->chipset); + if (!nvc) { + NOUVEAU_ERR("Failed initialising GPU context\n"); + return GL_FALSE; + } + nv_screen->nvc = nvc; + } + + nvc->refcount++; + nv->nvc = nvc; + + /* Find a free slot for a pipe context, allocate a new one if needed */ + nv->pctx_id = -1; + for (i = 0; i < nvc->nr_pctx; i++) { + if (nvc->pctx[i] == NULL) { + nv->pctx_id = i; + break; + } } + if (nv->pctx_id < 0) { + nv->pctx_id = nvc->nr_pctx++; + nvc->pctx = + realloc(nvc->pctx, + sizeof(struct pipe_context *) * nvc->nr_pctx); + } + + /* Create pipe */ if (nv->chipset < 0x50) ret = nouveau_surface_init_nv04(nv); else @@ -201,13 +247,18 @@ void nouveau_context_destroy(__DRIcontextPrivate *driContextPriv) { struct nouveau_context *nv = driContextPriv->driverPrivate; + struct nouveau_channel_context *nvc = nv->nvc; assert(nv); st_flush(nv->st, PIPE_FLUSH_WAIT); st_destroy_context(nv->st); - nouveau_channel_context_destroy(nv->nvc); + if (nv->pctx_id >= 0) { + nvc->pctx[nv->pctx_id] = NULL; + if (--nvc->refcount <= 0) + nouveau_channel_context_destroy(nvc); + } free(nv); } diff --git a/src/gallium/winsys/dri/nouveau/nouveau_context.h b/src/gallium/winsys/dri/nouveau/nouveau_context.h index 736c8d8bef..92f551855a 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_context.h +++ b/src/gallium/winsys/dri/nouveau/nouveau_context.h @@ -14,6 +14,13 @@ struct nouveau_framebuffer { }; struct nouveau_channel_context { + struct pipe_screen *pscreen; + int refcount; + + unsigned cur_pctx; + unsigned nr_pctx; + struct pipe_context **pctx; + unsigned chipset; struct nouveau_channel *channel; @@ -51,6 +58,7 @@ struct nouveau_context { /* Hardware context */ struct nouveau_channel_context *nvc; + int pctx_id; /* pipe_surface accel */ struct pipe_surface *surf_src, *surf_dst; diff --git a/src/gallium/winsys/dri/nouveau/nouveau_screen.h b/src/gallium/winsys/dri/nouveau/nouveau_screen.h index 019823bd44..e9da202690 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_screen.h +++ b/src/gallium/winsys/dri/nouveau/nouveau_screen.h @@ -14,6 +14,8 @@ struct nouveau_screen { uint32_t front_pitch; uint32_t front_cpp; uint32_t front_height; + + void *nvc; }; #endif diff --git a/src/gallium/winsys/dri/nouveau/nouveau_winsys.c b/src/gallium/winsys/dri/nouveau/nouveau_winsys.c index 50d7549b1b..87619bdcfb 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_winsys.c +++ b/src/gallium/winsys/dri/nouveau/nouveau_winsys.c @@ -70,11 +70,12 @@ nouveau_pipe_emit_reloc(struct nouveau_channel *chan, void *ptr, struct pipe_context * nouveau_pipe_create(struct nouveau_context *nv) { + struct nouveau_channel_context *nvc = nv->nvc; struct nouveau_winsys *nvws = CALLOC_STRUCT(nouveau_winsys); struct pipe_screen *(*hws_create)(struct pipe_winsys *, struct nouveau_winsys *, unsigned chipset); - struct pipe_context *(*hw_create)(struct pipe_screen *); + struct pipe_context *(*hw_create)(struct pipe_screen *, unsigned); struct pipe_winsys *ws; struct pipe_screen *pscreen; @@ -125,7 +126,10 @@ nouveau_pipe_create(struct nouveau_context *nv) nvws->surface_fill = nouveau_pipe_surface_fill; ws = nouveau_create_pipe_winsys(nv); - pscreen = hws_create(ws, nvws, nv->chipset); - return hw_create(pscreen); + + if (!nvc->pscreen) + nvc->pscreen = hws_create(ws, nvws, nv->chipset); + nvc->pctx[nv->pctx_id] = hw_create(nvc->pscreen, nv->pctx_id); + return nvc->pctx[nv->pctx_id]; } -- cgit v1.2.3