nouveau: enable multi-context/single-channel support for nv40
authorBen Skeggs <skeggsb@gmail.com>
Sun, 2 Mar 2008 03:56:42 +0000 (14:56 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Sun, 2 Mar 2008 04:02:25 +0000 (15:02 +1100)
src/gallium/drivers/nouveau/nouveau_winsys.h
src/gallium/drivers/nv30/nv30_context.c
src/gallium/drivers/nv40/nv40_context.c
src/gallium/drivers/nv40/nv40_context.h
src/gallium/drivers/nv40/nv40_screen.h
src/gallium/drivers/nv40/nv40_state_emit.c
src/gallium/drivers/nv50/nv50_context.c
src/gallium/winsys/dri/nouveau/nouveau_context.c
src/gallium/winsys/dri/nouveau/nouveau_context.h
src/gallium/winsys/dri/nouveau/nouveau_screen.h
src/gallium/winsys/dri/nouveau/nouveau_winsys.c

index 11ca7e8..44c8bb9 100644 (file)
@@ -54,20 +54,20 @@ nv30_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *,
                   unsigned chipset);
 
 extern struct pipe_context *
-nv30_create(struct pipe_screen *);
+nv30_create(struct pipe_screen *, unsigned pctx_id);
 
 extern struct pipe_screen *
 nv40_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *,
                   unsigned chipset);
 
 extern struct pipe_context *
-nv40_create(struct pipe_screen *);
+nv40_create(struct pipe_screen *, unsigned pctx_id);
 
 extern struct pipe_screen *
 nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *,
                   unsigned chipset);
 
 extern struct pipe_context *
-nv50_create(struct pipe_screen *);
+nv50_create(struct pipe_screen *, unsigned pctx_id);
 
 #endif
index 522fb13..28d3f05 100644 (file)
@@ -265,7 +265,7 @@ nv30_init_hwctx(struct nv30_context *nv30, int rankine_class)
 #define NV35TCL_CHIPSET_3X_MASK 0x000001e0
 
 struct pipe_context *
-nv30_create(struct pipe_screen *screen)
+nv30_create(struct pipe_screen *screen, unsigned pctx_id)
 {
        struct pipe_winsys *pipe_winsys = screen->winsys;
        struct nouveau_winsys *nvws = nv30_screen(screen)->nvws;
index 084829c..203c843 100644 (file)
@@ -44,7 +44,7 @@ nv40_destroy(struct pipe_context *pipe)
 }
 
 struct pipe_context *
-nv40_create(struct pipe_screen *pscreen)
+nv40_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
        struct nv40_screen *screen = nv40_screen(pscreen);
        struct pipe_winsys *ws = pscreen->winsys;
@@ -56,6 +56,7 @@ nv40_create(struct pipe_screen *pscreen)
        if (!nv40)
                return NULL;
        nv40->screen = screen;
+       nv40->pctx_id = pctx_id;
 
        nv40->chipset = chipset;
        nv40->nvws = nvws;
index 3b66959..e118776 100644 (file)
@@ -108,6 +108,7 @@ struct nv40_context {
 
        struct nouveau_winsys *nvws;
        struct nv40_screen *screen;
+       unsigned pctx_id;
 
        struct draw_context *draw;
 
index 9f9668d..3ea78aa 100644 (file)
@@ -9,6 +9,8 @@ struct nv40_screen {
        struct nouveau_winsys *nvws;
        unsigned chipset;
 
+       unsigned cur_pctx;
+
        /* HW graphics objects */
        struct nouveau_grobj *curie;
        struct nouveau_notifier *sync;
index 2215036..a95e247 100644 (file)
@@ -62,8 +62,18 @@ static void
 nv40_state_emit(struct nv40_context *nv40)
 {
        struct nv40_state *state = &nv40->state;
+       struct nv40_screen *screen = nv40->screen;
        unsigned i, samplers;
 
+       if (nv40->pctx_id != screen->cur_pctx) {
+               for (i = 0; i < NV40_STATE_MAX; i++) {
+                       if (screen->state[i] != state->hw[i] && state->hw[i])
+                               state->dirty |= (1ULL << i);
+               }
+
+               screen->cur_pctx = nv40->pctx_id;
+       }
+
        while (state->dirty) {
                unsigned idx = ffsll(state->dirty) - 1;
 
index e5054e3..c937b8d 100644 (file)
@@ -56,7 +56,7 @@ nv50_init_hwctx(struct nv50_context *nv50, int tesla_class)
 #define GRCLASS5097_CHIPSETS 0x00000000
 #define GRCLASS8297_CHIPSETS 0x00000010
 struct pipe_context *
-nv50_create(struct pipe_screen *pscreen)
+nv50_create(struct pipe_screen *pscreen, unsigned pctx_id)
 {
        struct pipe_winsys *pipe_winsys = pscreen->winsys;
        struct nouveau_winsys *nvws = nv50_screen(pscreen)->nvws;
index 7915afa..dc852c9 100644 (file)
@@ -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);
 }
index 736c8d8..92f5518 100644 (file)
@@ -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;
index 019823b..e9da202 100644 (file)
@@ -14,6 +14,8 @@ struct nouveau_screen {
        uint32_t front_pitch;
        uint32_t front_cpp;
        uint32_t front_height;
+
+       void *nvc;
 };
 
 #endif
index 50d7549..87619bd 100644 (file)
@@ -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];
 }