r300g: prevent CS overflow when emitting the draw packets
authorMarek Olšák <maraeo@gmail.com>
Mon, 22 Feb 2010 14:11:29 +0000 (15:11 +0100)
committerCorbin Simpson <MostAwesomeDude@gmail.com>
Thu, 25 Feb 2010 01:11:47 +0000 (17:11 -0800)
Signed-off-by: Corbin Simpson <MostAwesomeDude@gmail.com>
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_emit.h
src/gallium/drivers/r300/r300_render.c

index f7dcd8dc52fae8622d5227ca0cfbb5a256750784..2d8801c08ad91d98061421c286c1c3ba2528fe1f 100644 (file)
@@ -1076,16 +1076,10 @@ validate:
     }
 }
 
-/* Emit all dirty state. */
-void r300_emit_dirty_state(struct r300_context* r300)
+unsigned r300_get_num_dirty_dwords(struct r300_context *r300)
 {
-    struct r300_screen* r300screen = r300_screen(r300->context.screen);
     struct r300_atom* atom;
-    unsigned i, dwords = 1024;
-    int dirty_tex = 0;
-
-    /* Check the required number of dwords against the space remaining in the
-     * current CS object. If we need more, then flush. */
+    unsigned dwords = 0;
 
     foreach(atom, &r300->atom_list) {
         if (atom->dirty || atom->always_dirty) {
@@ -1093,12 +1087,19 @@ void r300_emit_dirty_state(struct r300_context* r300)
         }
     }
 
-    /* Make sure we have at least 2*1024 spare dwords. */
-    /* XXX It would be nice to know the number of dwords we really need to
-     * XXX emit. */
-    while (!r300->winsys->check_cs(r300->winsys, dwords)) {
-        r300->context.flush(&r300->context, 0, NULL);
-    }
+    /* XXX This is the compensation for the non-atomized states. */
+    dwords += 2048;
+
+    return dwords;
+}
+
+/* Emit all dirty state. */
+void r300_emit_dirty_state(struct r300_context* r300)
+{
+    struct r300_screen* r300screen = r300_screen(r300->context.screen);
+    struct r300_atom* atom;
+    unsigned i;
+    int dirty_tex = 0;
 
     if (r300->dirty_state & R300_NEW_QUERY) {
         r300_emit_query_start(r300);
index 6b96d9b57c0f3ec9d2bbccd476324e9dddfa970a..ff709a059570af0d356b29ebbc827d1eeee7bb15 100644 (file)
@@ -90,6 +90,8 @@ void r300_emit_ztop_state(struct r300_context* r300, void* state);
 
 void r300_flush_textures(struct r300_context* r300);
 
+unsigned r300_get_num_dirty_dwords(struct r300_context *r300);
+
 /* Emit all dirty state. */
 void r300_emit_dirty_state(struct r300_context* r300);
 
index 648d884654f0cf9848de9fc0fc5b2446d81c9a31..ec72d6c3b52ecb23d426f32c6bc5aa86df7f86ac 100644 (file)
@@ -118,6 +118,18 @@ static uint32_t r300_provoking_vertex_fixes(struct r300_context *r300,
     return color_control;
 }
 
+/* Check if the requested number of dwords is available in the CS and
+ * if not, flush. Return TRUE if the flush occured. */
+static boolean r300_reserve_cs_space(struct r300_context *r300,
+                                     unsigned dwords)
+{
+    while (!r300->winsys->check_cs(r300->winsys, dwords)) {
+        r300->context.flush(&r300->context, 0, NULL);
+        return TRUE;
+    }
+    return FALSE;
+}
+
 static boolean immd_is_good_idea(struct r300_context *r300,
                                       unsigned count)
 {
@@ -132,7 +144,7 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
     struct pipe_vertex_element* velem;
     struct pipe_vertex_buffer* vbuf;
     unsigned vertex_element_count = r300->vertex_element_count;
-    unsigned i, v, vbi, dw, elem_offset;
+    unsigned i, v, vbi, dw, elem_offset, dwords;
 
     /* Size of the vertex, in dwords. */
     unsigned vertex_size = 0;
@@ -171,9 +183,12 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
         }
     }
 
+    dwords = 10 + count * vertex_size;
+
+    r300_reserve_cs_space(r300, r300_get_num_dirty_dwords(r300) + dwords);
     r300_emit_dirty_state(r300);
 
-    BEGIN_CS(10 + count * vertex_size);
+    BEGIN_CS(dwords);
     OUT_CS_REG(R300_GA_COLOR_CONTROL,
             r300_provoking_vertex_fixes(r300, mode));
     OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size);
@@ -400,8 +415,9 @@ void r300_draw_range_elements(struct pipe_context* pipe,
         goto cleanup;
     }
 
+    /* 128 dwords for emit_aos and emit_draw_elements */
+    r300_reserve_cs_space(r300, r300_get_num_dirty_dwords(r300) + 128);
     r300_emit_dirty_state(r300);
-
     r300_emit_aos(r300, 0);
 
     if (alt_num_verts || count <= 65535) {
@@ -415,6 +431,12 @@ void r300_draw_range_elements(struct pipe_context* pipe,
 
             start += short_count;
             count -= short_count;
+
+            /* 16 spare dwords are enough for emit_draw_elements. */
+            if (count && r300_reserve_cs_space(r300, 16)) {
+                r300_emit_dirty_state(r300);
+                r300_emit_aos(r300, 0);
+            }
         } while (count);
     }
 
@@ -461,6 +483,9 @@ void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
             return;
         }
 
+        /* Make sure there are at least 128 spare dwords in the command buffer.
+         * (most of it being consumed by emit_aos) */
+        r300_reserve_cs_space(r300, r300_get_num_dirty_dwords(r300) + 128);
         r300_emit_dirty_state(r300);
 
         if (alt_num_verts || count <= 65535) {
@@ -474,6 +499,12 @@ void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
 
                 start += short_count;
                 count -= short_count;
+
+                /* Again, we emit both AOS and draw_arrays so there should be
+                 * at least 128 spare dwords. */
+                if (count && r300_reserve_cs_space(r300, 128)) {
+                    r300_emit_dirty_state(r300);
+                }
             } while (count);
         }
     }
@@ -690,6 +721,7 @@ static void r300_render_draw_arrays(struct vbuf_render* render,
 
     CS_LOCALS(r300);
 
+    r300_reserve_cs_space(r300, r300_get_num_dirty_dwords(r300) + 2);
     r300_emit_dirty_state(r300);
 
     DBG(r300, DBG_DRAW, "r300: Doing vbuf render, count %d\n", count);
@@ -708,12 +740,14 @@ static void r300_render_draw(struct vbuf_render* render,
     struct r300_render* r300render = r300_render(render);
     struct r300_context* r300 = r300render->r300;
     int i;
+    unsigned dwords = 2 + (count+1)/2;
 
     CS_LOCALS(r300);
 
+    r300_reserve_cs_space(r300, r300_get_num_dirty_dwords(r300) + dwords);
     r300_emit_dirty_state(r300);
 
-    BEGIN_CS(2 + (count+1)/2);
+    BEGIN_CS(dwords);
     OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, (count+1)/2);
     OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) |
            r300render->hwprim);