From 558f3abb49475ba0aad585e7fb0c07121aecde6f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 23 Nov 2007 18:54:11 +1100 Subject: nv40: support for keeping multiple vtxprogs on the hw at the same time. --- src/mesa/pipe/nouveau/nouveau_winsys.h | 17 ++++++ src/mesa/pipe/nv40/nv40_context.c | 8 +++ src/mesa/pipe/nv40/nv40_context.h | 11 ++-- src/mesa/pipe/nv40/nv40_fragprog.c | 2 +- src/mesa/pipe/nv40/nv40_state.c | 4 +- src/mesa/pipe/nv40/nv40_state.h | 8 ++- src/mesa/pipe/nv40/nv40_state_emit.c | 53 ++-------------- src/mesa/pipe/nv40/nv40_vbo.c | 2 +- src/mesa/pipe/nv40/nv40_vertprog.c | 108 ++++++++++++++++++++++++++++++--- 9 files changed, 144 insertions(+), 69 deletions(-) (limited to 'src/mesa/pipe') diff --git a/src/mesa/pipe/nouveau/nouveau_winsys.h b/src/mesa/pipe/nouveau/nouveau_winsys.h index beee49a134..28f17cdc8f 100644 --- a/src/mesa/pipe/nouveau/nouveau_winsys.h +++ b/src/mesa/pipe/nouveau/nouveau_winsys.h @@ -3,6 +3,7 @@ #include #include "pipe/p_winsys.h" +#include "pipe/p_defines.h" #include "pipe/nouveau/nouveau_bo.h" #include "pipe/nouveau/nouveau_channel.h" @@ -10,11 +11,27 @@ #include "pipe/nouveau/nouveau_grobj.h" #include "pipe/nouveau/nouveau_notifier.h" +struct nouveau_resource { + struct nouveau_resource *prev; + struct nouveau_resource *next; + + boolean in_use; + void *priv; + + uint start; + uint size; +}; + struct nouveau_winsys { struct nouveau_context *nv; struct nouveau_channel *channel; + int (*res_init)(struct nouveau_resource **heap, int size); + int (*res_alloc)(struct nouveau_resource *heap, int size, void *priv, + struct nouveau_resource **); + void (*res_free)(struct nouveau_resource **); + /*XXX: this is crappy, and bound to be slow.. however, it's nice and * simple, it'll do for the moment*/ uint32_t *(*begin_ring)(struct nouveau_grobj *, int mthd, int size); diff --git a/src/mesa/pipe/nv40/nv40_context.c b/src/mesa/pipe/nv40/nv40_context.c index 6f27091643..ba9d875e0e 100644 --- a/src/mesa/pipe/nv40/nv40_context.c +++ b/src/mesa/pipe/nv40/nv40_context.c @@ -241,6 +241,14 @@ nv40_create(struct pipe_winsys *pipe_winsys, struct nouveau_winsys *nvws, return NULL; } + if (nvws->res_init(&nv40->vertprog.exec_heap, 512) || + nvws->res_init(&nv40->vertprog.data_heap, 256)) { + nvws->res_free(&nv40->vertprog.exec_heap); + nvws->res_free(&nv40->vertprog.data_heap); + free(nv40); + return NULL; + } + if (!nv40_init_hwctx(nv40, curie_class)) { free(nv40); return NULL; diff --git a/src/mesa/pipe/nv40/nv40_context.h b/src/mesa/pipe/nv40/nv40_context.h index 63be38299f..ec07a88370 100644 --- a/src/mesa/pipe/nv40/nv40_context.h +++ b/src/mesa/pipe/nv40/nv40_context.h @@ -44,16 +44,19 @@ struct nv40_context { uint32_t tex_dirty; struct { - struct nv40_vertex_program *vp; - struct nv40_vertex_program *active_vp; + struct nouveau_resource *exec_heap; + struct nouveau_resource *data_heap; + struct nv40_vertex_program *active; + + struct nv40_vertex_program *current; struct pipe_buffer_handle *constant_buf; } vertprog; struct { - struct nv40_fragment_program *fp; - struct nv40_fragment_program *active_fp; + struct nv40_fragment_program *active; + struct nv40_fragment_program *current; struct pipe_buffer_handle *constant_buf; } fragprog; diff --git a/src/mesa/pipe/nv40/nv40_fragprog.c b/src/mesa/pipe/nv40/nv40_fragprog.c index a5c562ef71..09b68513ba 100644 --- a/src/mesa/pipe/nv40/nv40_fragprog.c +++ b/src/mesa/pipe/nv40/nv40_fragprog.c @@ -645,6 +645,6 @@ nv40_fragprog_bind(struct nv40_context *nv40, struct nv40_fragment_program *fp) BEGIN_RING(curie, NV40TCL_FP_CONTROL, 1); OUT_RING (fp_control); - nv40->fragprog.active_fp = fp; + nv40->fragprog.active = fp; } diff --git a/src/mesa/pipe/nv40/nv40_state.c b/src/mesa/pipe/nv40/nv40_state.c index 9b58409e51..b1928a5f91 100644 --- a/src/mesa/pipe/nv40/nv40_state.c +++ b/src/mesa/pipe/nv40/nv40_state.c @@ -443,7 +443,7 @@ nv40_vp_state_bind(struct pipe_context *pipe, void *hwcso) struct nv40_context *nv40 = (struct nv40_context *)pipe; struct nv40_vertex_program *vp = hwcso; - nv40->vertprog.vp = vp; + nv40->vertprog.current = vp; nv40->dirty |= NV40_NEW_VERTPROG; } @@ -471,7 +471,7 @@ nv40_fp_state_bind(struct pipe_context *pipe, void *hwcso) struct nv40_context *nv40 = (struct nv40_context *)pipe; struct nv40_fragment_program *fp = hwcso; - nv40->fragprog.fp = fp; + nv40->fragprog.current = fp; nv40->dirty |= NV40_NEW_FRAGPROG; } diff --git a/src/mesa/pipe/nv40/nv40_state.h b/src/mesa/pipe/nv40/nv40_state.h index 14bf5d83e3..d0114972ef 100644 --- a/src/mesa/pipe/nv40/nv40_state.h +++ b/src/mesa/pipe/nv40/nv40_state.h @@ -57,11 +57,13 @@ struct nv40_vertex_program { const struct pipe_shader_state *pipe; boolean translated; - boolean on_hw; - int start_ip; + struct nouveau_resource *exec; uint32_t *insn; - int insn_len; + uint insn_len; + + struct nouveau_resource *data; + uint data_start; struct { int pipe_id; diff --git a/src/mesa/pipe/nv40/nv40_state_emit.c b/src/mesa/pipe/nv40/nv40_state_emit.c index 3224c82999..55c7d36b12 100644 --- a/src/mesa/pipe/nv40/nv40_state_emit.c +++ b/src/mesa/pipe/nv40/nv40_state_emit.c @@ -6,7 +6,7 @@ static INLINE void nv40_state_update_fragprog(struct nv40_context *nv40) { struct pipe_context *pipe = (struct pipe_context *)nv40; - struct nv40_fragment_program *fp = nv40->fragprog.fp; + struct nv40_fragment_program *fp = nv40->fragprog.current; float *map; int i; @@ -36,57 +36,18 @@ nv40_state_update_fragprog(struct nv40_context *nv40) } } -static INLINE void -nv40_state_update_vertprog(struct nv40_context *nv40) -{ - struct pipe_context *pipe = (struct pipe_context *)nv40; - struct nv40_vertex_program *vp = nv40->vertprog.vp; - float *map; - int i, force_consts = 0; - - if (!nv40->vertprog.vp->translated) - nv40_vertprog_translate(nv40, nv40->vertprog.vp); - - if (nv40->vertprog.vp != nv40->vertprog.active_vp) - force_consts = 1; - - if (vp->num_consts) { - map = pipe->winsys->buffer_map(pipe->winsys, - nv40->vertprog.constant_buf, - PIPE_BUFFER_FLAG_READ); - for (i = 0; i < vp->num_consts; i++) { - uint pid = vp->consts[i].pipe_id; - - if (pid >= 0) { - if (!force_consts && - !memcmp(vp->consts[i].value, &map[pid*4], - 4 * sizeof(float))) - continue; - memcpy(vp->consts[i].value, &map[pid*4], - 4 * sizeof(float)); - } - - BEGIN_RING(curie, NV40TCL_VP_UPLOAD_CONST_ID, 5); - OUT_RING (vp->consts[i].hw_id); - OUT_RINGp ((uint32_t *)vp->consts[i].value, 4); - } - pipe->winsys->buffer_unmap(pipe->winsys, - nv40->vertprog.constant_buf); - } -} - void nv40_emit_hw_state(struct nv40_context *nv40) { if (nv40->dirty & NV40_NEW_FRAGPROG) { - struct nv40_fragment_program *cur = nv40->fragprog.fp; + struct nv40_fragment_program *cur = nv40->fragprog.current; nv40_state_update_fragprog(nv40); if (cur->on_hw) nv40->dirty &= ~NV40_NEW_FRAGPROG; - if (!cur->on_hw || cur != nv40->fragprog.active_fp) + if (!cur->on_hw || cur != nv40->fragprog.active) nv40_fragprog_bind(nv40, cur); } @@ -101,12 +62,8 @@ nv40_emit_hw_state(struct nv40_context *nv40) nv40->dirty &= ~(NV40_NEW_TEXTURE | NV40_NEW_FRAGPROG); } - if (nv40->dirty & NV40_NEW_VERTPROG) { - nv40_state_update_vertprog(nv40); - if (nv40->vertprog.vp != nv40->vertprog.active_vp) - nv40_vertprog_bind(nv40, nv40->vertprog.vp); - nv40->dirty &= ~NV40_NEW_VERTPROG; - } + if (nv40->dirty & NV40_NEW_VERTPROG) + nv40_vertprog_bind(nv40, nv40->vertprog.current); if (nv40->dirty & NV40_NEW_ARRAYS) { nv40_vbo_arrays_update(nv40); diff --git a/src/mesa/pipe/nv40/nv40_vbo.c b/src/mesa/pipe/nv40/nv40_vbo.c index aa930476b6..2da0001b28 100644 --- a/src/mesa/pipe/nv40/nv40_vbo.c +++ b/src/mesa/pipe/nv40/nv40_vbo.c @@ -176,7 +176,7 @@ void nv40_vbo_arrays_update(struct nv40_context *nv40) { struct nouveau_winsys *nvws = nv40->nvws; - struct nv40_vertex_program *vp = nv40->vertprog.vp; + struct nv40_vertex_program *vp = nv40->vertprog.active; uint32_t inputs, vtxfmt[16]; int hw, num_hw; diff --git a/src/mesa/pipe/nv40/nv40_vertprog.c b/src/mesa/pipe/nv40/nv40_vertprog.c index 68334b7420..04bdaacc98 100644 --- a/src/mesa/pipe/nv40/nv40_vertprog.c +++ b/src/mesa/pipe/nv40/nv40_vertprog.c @@ -576,21 +576,108 @@ out_err: void nv40_vertprog_bind(struct nv40_context *nv40, struct nv40_vertex_program *vp) { + struct nouveau_winsys *nvws = nv40->nvws; + struct pipe_context *pipe = &nv40->pipe; + boolean upload_code = FALSE, upload_data = FALSE; + float *map; int i; + /* Translate TGSI shader into hw bytecode */ if (!vp->translated) { - NOUVEAU_ERR("vtxprog invalid, using passthrough shader\n"); - vp = &passthrough_vp; + nv40_vertprog_translate(nv40, vp); + if (!vp->translated) + assert(0); } - if (!vp->on_hw) { - if (nv40->vertprog.active_vp) - nv40->vertprog.active_vp->on_hw = FALSE; - vp->on_hw = TRUE; - vp->start_ip = 0; + /* Allocate hw vtxprog exec slots */ + /*XXX: when we do branching, need to patch targets if program moves. + */ + if (!vp->exec) { + struct nouveau_resource *heap = nv40->vertprog.exec_heap; + uint vplen = vp->insn_len / 4; + + if (nvws->res_alloc(heap, vplen, vp, &vp->exec)) { + while (heap->next && heap->size < vplen) { + struct nv40_vertex_program *evict; + + evict = heap->next->priv; + nvws->res_free(&evict->exec); + } + + if (nvws->res_alloc(heap, vplen, vp, &vp->exec)) + assert(0); + } + + upload_code = TRUE; + } + + /* Allocate hw vtxprog const slots */ + if (vp->num_consts && !vp->data) { + struct nouveau_resource *heap = nv40->vertprog.data_heap; + int count = vp->num_consts; + + if (nvws->res_alloc(heap, count, vp, &vp->data)) { + while (heap->next && heap->size < count) { + struct nv40_vertex_program *evict; + + evict = heap->next->priv; + nvws->res_free(&evict->data); + } + + if (nvws->res_alloc(heap, count, vp, &vp->data)) + assert(0); + } + + upload_data = TRUE; + } + + /* If constants moved, patch the vtxprog to fix the offsets */ + if (vp->num_consts && vp->data_start != vp->data->start) { + for (i = 0; i < vp->insn_len; i += 4) { + int id; + + id = (vp->insn[i + 1] & NV40_VP_INST_CONST_SRC_MASK) >> + NV40_VP_INST_CONST_SRC_SHIFT; + id -= vp->data_start; + id += vp->data->start; + + vp->insn[i + 1] &= ~NV40_VP_INST_CONST_SRC_MASK; + vp->insn[i + 1] |= (id << NV40_VP_INST_CONST_SRC_SHIFT); + } + + vp->data_start = vp->data->start; + upload_code = TRUE; + } + /* Update + Upload constant values */ + if (vp->num_consts) { + map = pipe->winsys->buffer_map(pipe->winsys, + nv40->vertprog.constant_buf, + PIPE_BUFFER_FLAG_READ); + for (i = 0; i < vp->num_consts; i++) { + uint pid = vp->consts[i].pipe_id; + + if (pid >= 0) { + if (!upload_data && + !memcmp(vp->consts[i].value, &map[pid*4], + 4 * sizeof(float))) + continue; + memcpy(vp->consts[i].value, &map[pid*4], + 4 * sizeof(float)); + } + + BEGIN_RING(curie, NV40TCL_VP_UPLOAD_CONST_ID, 5); + OUT_RING (vp->consts[i].hw_id + vp->data->start); + OUT_RINGp ((uint32_t *)vp->consts[i].value, 4); + } + pipe->winsys->buffer_unmap(pipe->winsys, + nv40->vertprog.constant_buf); + } + + /* Upload vtxprog */ + if (upload_code) { BEGIN_RING(curie, NV40TCL_VP_UPLOAD_FROM_ID, 1); - OUT_RING (vp->start_ip); + OUT_RING (vp->exec->start); for (i = 0; i < vp->insn_len; i += 4) { BEGIN_RING(curie, NV40TCL_VP_UPLOAD_INST(0), 4); OUT_RINGp (&vp->insn[i], 4); @@ -598,10 +685,11 @@ nv40_vertprog_bind(struct nv40_context *nv40, struct nv40_vertex_program *vp) } BEGIN_RING(curie, NV40TCL_VP_START_FROM_ID, 1); - OUT_RING (vp->start_ip); + OUT_RING (vp->exec->start); BEGIN_RING(curie, NV40TCL_VP_ATTRIB_EN, 2); OUT_RING (vp->ir); OUT_RING (vp->or); - nv40->vertprog.active_vp = vp; + nv40->vertprog.active = vp; } + -- cgit v1.2.3