nv40: prep for multiple pipe contexts on a single hw channel
[mesa.git] / src / mesa / pipe / nv40 / nv40_context.c
index 518ba3574f7a446413476845a0447709e1259390..4343d493cc519187eb9c639bde850aad612231a3 100644 (file)
@@ -4,27 +4,15 @@
 #include "pipe/p_util.h"
 
 #include "nv40_context.h"
-#include "nv40_dma.h"
 
-static boolean
-nv40_is_format_supported(struct pipe_context *pipe, uint format)
-{
-       switch (format) {
-       case PIPE_FORMAT_A8R8G8B8_UNORM:
-       case PIPE_FORMAT_R5G6B5_UNORM: 
-       case PIPE_FORMAT_Z24S8_UNORM:
-               return TRUE;
-       default:
-               break;
-       };
-
-       return FALSE;
-}
+#define NV4X_GRCLASS4097_CHIPSETS 0x00000baf
+#define NV4X_GRCLASS4497_CHIPSETS 0x00005450
+#define NV6X_GRCLASS4497_CHIPSETS 0x00000080
 
 static const char *
 nv40_get_name(struct pipe_context *pipe)
 {
-       struct nv40_context *nv40 = (struct nv40_context *)pipe;
+       struct nv40_context *nv40 = nv40_context(pipe);
        static char buffer[128];
 
        snprintf(buffer, sizeof(buffer), "NV%02X", nv40->chipset);
@@ -60,7 +48,7 @@ nv40_get_param(struct pipe_context *pipe, int param)
        case PIPE_CAP_OCCLUSION_QUERY:
                return 1;
        case PIPE_CAP_TEXTURE_SHADOW_MAP:
-               return 0;
+               return 1;
        case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
                return 13;
        case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
@@ -87,6 +75,8 @@ nv40_get_paramf(struct pipe_context *pipe, int param)
                return 16.0;
        case PIPE_CAP_MAX_TEXTURE_LOD_BIAS:
                return 4.0;
+       case PIPE_CAP_BITMAP_TEXCOORD_BIAS:
+               return 0.0;
        default:
                NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param);
                return 0.0;
@@ -96,7 +86,7 @@ nv40_get_paramf(struct pipe_context *pipe, int param)
 static void
 nv40_flush(struct pipe_context *pipe, unsigned flags)
 {
-       struct nv40_context *nv40 = (struct nv40_context *)pipe;
+       struct nv40_context *nv40 = nv40_context(pipe);
        struct nouveau_winsys *nvws = nv40->nvws;
        
        if (flags & PIPE_FLUSH_TEXTURE_CACHE) {
@@ -107,7 +97,7 @@ nv40_flush(struct pipe_context *pipe, unsigned flags)
        }
 
        if (flags & PIPE_FLUSH_WAIT) {
-               nvws->notifier_reset(nv40->sync, 0);
+               nvws->notifier_reset(nv40->hw->sync, 0);
                BEGIN_RING(curie, 0x104, 1);
                OUT_RING  (0);
                BEGIN_RING(curie, 0x100, 1);
@@ -117,156 +107,195 @@ nv40_flush(struct pipe_context *pipe, unsigned flags)
        FIRE_RING();
 
        if (flags & PIPE_FLUSH_WAIT)
-               nvws->notifier_wait(nv40->sync, 0, 0, 2000);
+               nvws->notifier_wait(nv40->hw->sync, 0, 0, 2000);
 }
 
 static void
-nv40_destroy(struct pipe_context *pipe)
+nv40_channel_takedown(struct nv40_channel_context *cnv40)
 {
-       struct nv40_context *nv40 = (struct nv40_context *)pipe;
-
-       draw_destroy(nv40->draw);
-       free(nv40);
+       struct nouveau_winsys *nvws = cnv40->nvws;
+
+       nvws->res_free(&cnv40->vp_exec_heap);
+       nvws->res_free(&cnv40->vp_data_heap);
+       nvws->res_free(&cnv40->query_heap);
+       nvws->notifier_free(&cnv40->query);
+       nvws->notifier_free(&cnv40->sync);
+       nvws->grobj_free(&cnv40->curie);
+       free(cnv40);
 }
 
-static boolean
-nv40_init_hwctx(struct nv40_context *nv40, int curie_class)
+static struct nv40_channel_context *
+nv40_channel_init(struct pipe_winsys *ws, struct nouveau_winsys *nvws,
+                 unsigned chipset)
 {
-       struct nouveau_winsys *nvws = nv40->nvws;
+       struct nv40_channel_context *cnv40 = NULL;
+       struct nouveau_stateobj *so;
+       unsigned curie_class = 0;
        int ret;
 
-       if ((ret = nvws->notifier_alloc(nvws, nv40->num_query_objects,
-                                       &nv40->query))) {
-               NOUVEAU_ERR("Error creating query notifier objects: %d\n", ret);
-               return FALSE;
+       switch (chipset & 0xf0) {
+       case 0x40:
+               if (NV4X_GRCLASS4097_CHIPSETS & (1 << (chipset & 0x0f)))
+                       curie_class = NV40TCL;
+               else
+               if (NV4X_GRCLASS4497_CHIPSETS & (1 << (chipset & 0x0f)))
+                       curie_class = NV44TCL;
+               break;
+       case 0x60:
+               if (NV6X_GRCLASS4497_CHIPSETS & (1 << (chipset & 0x0f)))
+                       curie_class = NV44TCL;
+               break;
+       default:
+               break;
        }
 
-       if ((ret = nvws->grobj_alloc(nvws, curie_class,
-                                    &nv40->curie))) {
-               NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
-               return FALSE;
+       if (!curie_class) {
+               NOUVEAU_ERR("Unknown nv4x chipset: nv%02x\n", chipset);
+               return NULL;
        }
 
-       BEGIN_RING(curie, NV40TCL_DMA_NOTIFY, 1);
-       OUT_RING  (nv40->sync->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_TEXTURE0, 2);
-       OUT_RING  (nvws->channel->vram->handle);
-       OUT_RING  (nvws->channel->gart->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_COLOR1, 1);
-       OUT_RING  (nvws->channel->vram->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_COLOR0, 2);
-       OUT_RING  (nvws->channel->vram->handle);
-       OUT_RING  (nvws->channel->vram->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_VTXBUF0, 2);
-       OUT_RING  (nvws->channel->vram->handle);
-       OUT_RING  (nvws->channel->gart->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_FENCE, 2);
-       OUT_RING  (0);
-       OUT_RING  (nv40->query->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_UNK01AC, 2);
-       OUT_RING  (nvws->channel->vram->handle);
-       OUT_RING  (nvws->channel->vram->handle);
-       BEGIN_RING(curie, NV40TCL_DMA_COLOR2, 2);
-       OUT_RING  (nvws->channel->vram->handle);
-       OUT_RING  (nvws->channel->vram->handle);
-
-       BEGIN_RING(curie, 0x1ea4, 3);
-       OUT_RING  (0x00000010);
-       OUT_RING  (0x01000100);
-       OUT_RING  (0xff800006);
-
-       /* vtxprog output routing */
-       BEGIN_RING(curie, 0x1fc4, 1);
-       OUT_RING  (0x06144321);
-       BEGIN_RING(curie, 0x1fc8, 2);
-       OUT_RING  (0xedcba987);
-       OUT_RING  (0x00000021);
-       BEGIN_RING(curie, 0x1fd0, 1);
-       OUT_RING  (0x00171615);
-       BEGIN_RING(curie, 0x1fd4, 1);
-       OUT_RING  (0x001b1a19);
-
-       BEGIN_RING(curie, 0x1ef8, 1);
-       OUT_RING  (0x0020ffff);
-       BEGIN_RING(curie, 0x1d64, 1);
-       OUT_RING  (0x00d30000);
-       BEGIN_RING(curie, 0x1e94, 1);
-       OUT_RING  (0x00000001);
-
-       FIRE_RING ();
-       return TRUE;
-}
-
-#define GRCLASS4097_CHIPSETS 0x00000baf
-#define GRCLASS4497_CHIPSETS 0x00005450
-struct pipe_context *
-nv40_create(struct pipe_winsys *pipe_winsys, struct nouveau_winsys *nvws,
-           unsigned chipset)
-{
-       struct nv40_context *nv40;
-       int curie_class, ret;
+       cnv40 = calloc(1, sizeof(struct nv40_channel_context));
+       if (!cnv40)
+               return NULL;
+       cnv40->chipset = chipset;
+       cnv40->nvws = nvws;
 
-       if ((chipset & 0xf0) != 0x40) {
-               NOUVEAU_ERR("Not a NV4X chipset\n");
+       /* Notifier for sync purposes */
+       ret = nvws->notifier_alloc(nvws, 1, &cnv40->sync);
+       if (ret) {
+               NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
+               nv40_channel_takedown(cnv40);
                return NULL;
        }
 
-       if (GRCLASS4097_CHIPSETS & (1 << (chipset & 0x0f))) {
-               curie_class = 0x4097;
-       } else
-       if (GRCLASS4497_CHIPSETS & (1 << (chipset & 0x0f))) {
-               curie_class = 0x4497;
-       } else {
-               NOUVEAU_ERR("Unknown NV4X chipset: NV%02x\n", chipset);
+       /* Query objects */
+       ret = nvws->notifier_alloc(nvws, 32, &cnv40->query);
+       if (ret) {
+               NOUVEAU_ERR("Error initialising query objects: %d\n", ret);
+               nv40_channel_takedown(cnv40);
                return NULL;
        }
 
-       nv40 = CALLOC_STRUCT(nv40_context);
-       if (!nv40)
+       ret = nvws->res_init(&cnv40->query_heap, 0, 32);
+       if (ret) {
+               NOUVEAU_ERR("Error initialising query object heap: %d\n", ret);
+               nv40_channel_takedown(cnv40);
                return NULL;
-       nv40->chipset = chipset;
-       nv40->nvws = nvws;
+       }
 
-       if ((ret = nvws->notifier_alloc(nvws, 1, &nv40->sync))) {
-               NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
-               free(nv40);
+       /* Vtxprog resources */
+       if (nvws->res_init(&cnv40->vp_exec_heap, 0, 512) ||
+           nvws->res_init(&cnv40->vp_data_heap, 0, 256)) {
+               nv40_channel_takedown(cnv40);
                return NULL;
        }
 
-       nv40->num_query_objects = 32;
-       nv40->query_objects = calloc(nv40->num_query_objects,
-                                    sizeof(struct pipe_query_object *));
-       if (!nv40->query_objects) {
-               free(nv40);
-               return NULL;
+       /* 3D object */
+       ret = nvws->grobj_alloc(nvws, curie_class, &cnv40->curie);
+       if (ret) {
+               NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
+               return FALSE;
        }
 
-       if (nvws->res_init(&nv40->vertprog.exec_heap, 0, 512) ||
-           nvws->res_init(&nv40->vertprog.data_heap, 0, 256)) {
-               nvws->res_free(&nv40->vertprog.exec_heap);
-               nvws->res_free(&nv40->vertprog.data_heap);
-               free(nv40);
-               return NULL;
+       /* Static curie initialisation */
+       so = so_new(128, 0);
+       so_method(so, cnv40->curie, NV40TCL_DMA_NOTIFY, 1);
+       so_data  (so, cnv40->sync->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_TEXTURE0, 2);
+       so_data  (so, nvws->channel->vram->handle);
+       so_data  (so, nvws->channel->gart->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_COLOR1, 1);
+       so_data  (so, nvws->channel->vram->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_COLOR0, 2);
+       so_data  (so, nvws->channel->vram->handle);
+       so_data  (so, nvws->channel->vram->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_VTXBUF0, 2);
+       so_data  (so, nvws->channel->vram->handle);
+       so_data  (so, nvws->channel->gart->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_FENCE, 2);
+       so_data  (so, 0);
+       so_data  (so, cnv40->query->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_UNK01AC, 2);
+       so_data  (so, nvws->channel->vram->handle);
+       so_data  (so, nvws->channel->vram->handle);
+       so_method(so, cnv40->curie, NV40TCL_DMA_COLOR2, 2);
+       so_data  (so, nvws->channel->vram->handle);
+       so_data  (so, nvws->channel->vram->handle);
+
+       so_method(so, cnv40->curie, 0x1ea4, 3);
+       so_data  (so, 0x00000010);
+       so_data  (so, 0x01000100);
+       so_data  (so, 0xff800006);
+
+       /* vtxprog output routing */
+       so_method(so, cnv40->curie, 0x1fc4, 1);
+       so_data  (so, 0x06144321);
+       so_method(so, cnv40->curie, 0x1fc8, 2);
+       so_data  (so, 0xedcba987);
+       so_data  (so, 0x00000021);
+       so_method(so, cnv40->curie, 0x1fd0, 1);
+       so_data  (so, 0x00171615);
+       so_method(so, cnv40->curie, 0x1fd4, 1);
+       so_data  (so, 0x001b1a19);
+
+       so_method(so, cnv40->curie, 0x1ef8, 1);
+       so_data  (so, 0x0020ffff);
+       so_method(so, cnv40->curie, 0x1d64, 1);
+       so_data  (so, 0x00d30000);
+       so_method(so, cnv40->curie, 0x1e94, 1);
+       so_data  (so, 0x00000001);
+
+       so_emit(nvws, so);
+       so_ref(NULL, &so);
+       nvws->push_flush(nvws->channel, 0);
+
+       return cnv40;
+}
+
+static void
+nv40_destroy(struct pipe_context *pipe)
+{
+       struct nv40_context *nv40 = nv40_context(pipe);
+
+       if (nv40->draw)
+               draw_destroy(nv40->draw);
+
+       if (nv40->hw) {
+               if (--nv40->hw->refcount == 0)
+                       nv40_channel_takedown(nv40->hw);
        }
 
-       if (!nv40_init_hwctx(nv40, curie_class)) {
-               free(nv40);
+       free(nv40);
+}
+
+struct pipe_context *
+nv40_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws,
+           unsigned chipset)
+{
+       struct nv40_context *nv40;
+
+       nv40 = calloc(1, sizeof(struct nv40_context));
+       if (!nv40)
+               return NULL;
+
+       nv40->hw = nv40_channel_init(ws, nvws, chipset);
+       if (!nv40->hw) {
+               nv40_destroy(&nv40->pipe);
                return NULL;
        }
 
-       nv40->pipe.winsys = pipe_winsys;
+       nv40->chipset = chipset;
+       nv40->nvws = nvws;
 
+       nv40->pipe.winsys = ws;
        nv40->pipe.destroy = nv40_destroy;
-       nv40->pipe.is_format_supported = nv40_is_format_supported;
        nv40->pipe.get_name = nv40_get_name;
        nv40->pipe.get_vendor = nv40_get_vendor;
        nv40->pipe.get_param = nv40_get_param;
        nv40->pipe.get_paramf = nv40_get_paramf;
-
        nv40->pipe.draw_arrays = nv40_draw_arrays;
        nv40->pipe.draw_elements = nv40_draw_elements;
        nv40->pipe.clear = nv40_clear;
-
        nv40->pipe.flush = nv40_flush;
 
        nv40_init_query_functions(nv40);
@@ -280,5 +309,4 @@ nv40_create(struct pipe_winsys *pipe_winsys, struct nouveau_winsys *nvws,
 
        return &nv40->pipe;
 }
-
-               
+