nv40: need to resubmit buffers if pushbuf gets flushed during draw
authorBen Skeggs <skeggsb@gmail.com>
Fri, 28 Mar 2008 12:51:24 +0000 (23:51 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Fri, 4 Apr 2008 01:17:27 +0000 (11:17 +1000)
src/gallium/drivers/nouveau/nouveau_util.h [new file with mode: 0644]
src/gallium/drivers/nv40/nv40_vbo.c

diff --git a/src/gallium/drivers/nouveau/nouveau_util.h b/src/gallium/drivers/nouveau/nouveau_util.h
new file mode 100644 (file)
index 0000000..c92041e
--- /dev/null
@@ -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
index bc53924a6762cc37989d571b11f656db5362da4f..33d3efb58d06dca85ba51a210949a8488c9dd06c 100644 (file)
@@ -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;
 }