diff options
author | Ben Skeggs <[email protected]> | 2008-03-28 23:51:24 +1100 |
---|---|---|
committer | Ben Skeggs <[email protected]> | 2008-04-04 11:17:27 +1000 |
commit | 73322bba5c7102f0e100c9a07273a7a87705cf55 (patch) | |
tree | 7d8a4aeb072563bcb94c544151ccf4f0fc375b87 /src/gallium/drivers | |
parent | 8ed894bd17bd6f426a0d87f7113f23043cda3bc3 (diff) |
nv40: need to resubmit buffers if pushbuf gets flushed during draw
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r-- | src/gallium/drivers/nouveau/nouveau_util.h | 64 | ||||
-rw-r--r-- | src/gallium/drivers/nv40/nv40_vbo.c | 120 |
2 files changed, 140 insertions, 44 deletions
diff --git a/src/gallium/drivers/nouveau/nouveau_util.h b/src/gallium/drivers/nouveau/nouveau_util.h new file mode 100644 index 00000000000..c92041ebeba --- /dev/null +++ b/src/gallium/drivers/nouveau/nouveau_util.h @@ -0,0 +1,64 @@ +#ifndef __NOUVEAU_UTIL_H__ +#define __NOUVEAU_UTIL_H__ + +/* Determine how many vertices can be pushed into the command stream. + * Where the remaining space isn't large enough to represent all verices, + * split the buffer at primitive boundaries. + * + * Returns a count of vertices that can be rendered, and an index to + * restart drawing at after a flush. + */ +static INLINE unsigned +nouveau_vbuf_split(unsigned remaining, unsigned overhead, unsigned vpp, + unsigned mode, unsigned start, unsigned count, + unsigned *restart) +{ + int max, adj = 0; + + max = remaining - overhead; + if (max < 0) + return 0; + + max *= vpp; + if (max >= count) + return count; + + switch (mode) { + case PIPE_PRIM_POINTS: + break; + case PIPE_PRIM_LINES: + max = max & 1; + break; + case PIPE_PRIM_TRIANGLES: + max = max - (max % 3); + break; + case PIPE_PRIM_QUADS: + max = max & 3; + break; + case PIPE_PRIM_LINE_LOOP: + case PIPE_PRIM_LINE_STRIP: + if (max < 2) + max = 0; + adj = 1; + break; + case PIPE_PRIM_POLYGON: + case PIPE_PRIM_TRIANGLE_STRIP: + case PIPE_PRIM_TRIANGLE_FAN: + if (max < 3) + max = 0; + adj = 2; + break; + case PIPE_PRIM_QUAD_STRIP: + if (max < 4) + max = 0; + adj = 3; + break; + default: + assert(0); + } + + *restart = start + max - adj; + return max; +} + +#endif diff --git a/src/gallium/drivers/nv40/nv40_vbo.c b/src/gallium/drivers/nv40/nv40_vbo.c index bc53924a676..33d3efb58d0 100644 --- a/src/gallium/drivers/nv40/nv40_vbo.c +++ b/src/gallium/drivers/nv40/nv40_vbo.c @@ -7,6 +7,7 @@ #include "nouveau/nouveau_channel.h" #include "nouveau/nouveau_pushbuf.h" +#include "nouveau/nouveau_util.h" #define FORCE_SWTNL 0 @@ -170,44 +171,60 @@ nv40_vbo_static_attrib(struct nv40_context *nv40, int attrib, } boolean -nv40_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start, - unsigned count) +nv40_draw_arrays(struct pipe_context *pipe, + unsigned mode, unsigned start, unsigned count) { struct nv40_context *nv40 = nv40_context(pipe); - unsigned nr; + struct nouveau_channel *chan = nv40->nvws->channel; + unsigned restart; nv40_vbo_set_idxbuf(nv40, NULL, 0); if (FORCE_SWTNL || !nv40_state_validate(nv40)) { return nv40_draw_elements_swtnl(pipe, NULL, 0, mode, start, count); } - nv40_state_emit(nv40); - BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); - OUT_RING (nvgl_primitive(mode)); + while (count) { + unsigned vc, nr; - nr = (count & 0xff); - if (nr) { - BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1); - OUT_RING (((nr - 1) << 24) | start); - start += nr; - } + nv40_state_emit(nv40); - nr = count >> 8; - while (nr) { - unsigned push = nr > 2047 ? 2047 : nr; + vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256, + mode, start, count, &restart); + if (!vc) { + FIRE_RING(NULL); + continue; + } - nr -= push; + BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); + OUT_RING (nvgl_primitive(mode)); - BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push); - while (push--) { - OUT_RING(((0x100 - 1) << 24) | start); - start += 0x100; + nr = (vc & 0xff); + if (nr) { + BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1); + OUT_RING (((nr - 1) << 24) | start); + start += nr; } - } - BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); - OUT_RING (0); + nr = vc >> 8; + while (nr) { + unsigned push = nr > 2047 ? 2047 : nr; + + nr -= push; + + BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push); + while (push--) { + OUT_RING(((0x100 - 1) << 24) | start); + start += 0x100; + } + } + + BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); + OUT_RING (0); + + count -= vc; + start = restart; + } pipe->flush(pipe, 0, NULL); return TRUE; @@ -329,35 +346,50 @@ nv40_draw_elements_vbo(struct pipe_context *pipe, unsigned mode, unsigned start, unsigned count) { struct nv40_context *nv40 = nv40_context(pipe); - unsigned nr; + struct nouveau_channel *chan = nv40->nvws->channel; + unsigned restart; - nv40_state_emit(nv40); + while (count) { + unsigned nr, vc; - BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); - OUT_RING (nvgl_primitive(mode)); + nv40_state_emit(nv40); - nr = (count & 0xff); - if (nr) { - BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1); - OUT_RING (((nr - 1) << 24) | start); - start += nr; - } + vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256, + mode, start, count, &restart); + if (!vc) { + FIRE_RING(NULL); + continue; + } + + BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); + OUT_RING (nvgl_primitive(mode)); + + nr = (vc & 0xff); + if (nr) { + BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1); + OUT_RING (((nr - 1) << 24) | start); + start += nr; + } - nr = count >> 8; - while (nr) { - unsigned push = nr > 2047 ? 2047 : nr; + nr = vc >> 8; + while (nr) { + unsigned push = nr > 2047 ? 2047 : nr; - nr -= push; + nr -= push; - BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push); - while (push--) { - OUT_RING(((0x100 - 1) << 24) | start); - start += 0x100; + BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push); + while (push--) { + OUT_RING(((0x100 - 1) << 24) | start); + start += 0x100; + } } - } - BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); - OUT_RING (0); + BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); + OUT_RING (0); + + count -= vc; + start = restart; + } return TRUE; } |