Mesa (master): r300g: fix SWTCL

Marek Olšák mareko at kemper.freedesktop.org
Mon Sep 13 11:27:37 UTC 2010


Module: Mesa
Branch: master
Commit: 0392e48867c27f2aa445c5c9b35f4a52ecef2f2d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0392e48867c27f2aa445c5c9b35f4a52ecef2f2d

Author: Marek Olšák <maraeo at gmail.com>
Date:   Mon Sep 13 12:58:19 2010 +0200

r300g: fix SWTCL

https://bugs.freedesktop.org/show_bug.cgi?id=29901

---

 src/gallium/drivers/r300/r300_context.h |   12 ++-
 src/gallium/drivers/r300/r300_emit.c    |    2 +-
 src/gallium/drivers/r300/r300_flush.c   |    2 +-
 src/gallium/drivers/r300/r300_render.c  |  124 ++++++++++++++++++++++---------
 4 files changed, 99 insertions(+), 41 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index 8f0e86f..8eddf72 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -447,9 +447,17 @@ struct r300_context {
     struct r300_winsys_cs *cs;
     /* Screen. */
     struct r300_screen *screen;
+
     /* Draw module. Used mostly for SW TCL. */
     struct draw_context* draw;
+    /* Vertex buffer for SW TCL. */
+    struct pipe_resource* vbo;
+    /* Offset and size into the SW TCL VBO. */
+    size_t draw_vbo_offset;
     size_t draw_vbo_size;
+    /* Whether the VBO must not be flushed. */
+    boolean draw_vbo_locked;
+
     /* Accelerated blit support. */
     struct blitter_context* blitter;
     /* Stencil two-sided reference value fallback. */
@@ -457,14 +465,10 @@ struct r300_context {
     /* For translating vertex buffers having incompatible vertex layout. */
     struct r300_translate_context tran;
 
-    /* Vertex buffer for rendering. */
-    struct pipe_resource* vbo;
     /* The KIL opcode needs the first texture unit to be enabled
      * on r3xx-r4xx. In order to calm down the CS checker, we bind this
      * dummy texture there. */
     struct r300_sampler_view *texkill_sampler;
-    /* Offset into the VBO. */
-    size_t vbo_offset;
 
     /* The currently active query. */
     struct r300_query *query_current;
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index 3eebd2a..b2b34c3 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -847,7 +847,7 @@ void r300_emit_aos_swtcl(struct r300_context *r300, boolean indexed)
     OUT_CS(1 | (!indexed ? R300_VC_FORCE_PREFETCH : 0));
     OUT_CS(r300->vertex_info.size |
             (r300->vertex_info.size << 8));
-    OUT_CS(r300->vbo_offset);
+    OUT_CS(r300->draw_vbo_offset);
     OUT_CS_BUF_RELOC(r300->vbo, 0, r300_buffer(r300->vbo)->domain, 0);
     END_CS;
 }
diff --git a/src/gallium/drivers/r300/r300_flush.c b/src/gallium/drivers/r300/r300_flush.c
index 2b5d2e4..1afd27f 100644
--- a/src/gallium/drivers/r300/r300_flush.c
+++ b/src/gallium/drivers/r300/r300_flush.c
@@ -43,7 +43,7 @@ static void r300_flush(struct pipe_context* pipe,
     u_upload_flush(r300->upload_vb);
     u_upload_flush(r300->upload_ib);
 
-    if (r300->draw)
+    if (r300->draw && !r300->draw_vbo_locked)
 	r300_draw_flush_vbuf(r300);
 
     if (r300->dirty_hw) {
diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c
index aa45ee3..6c4cd6c 100644
--- a/src/gallium/drivers/r300/r300_render.c
+++ b/src/gallium/drivers/r300/r300_render.c
@@ -179,26 +179,20 @@ enum r300_prepare_flags {
 
 /**
  * Check if the requested number of dwords is available in the CS and
- * if not, flush. Then validate buffers and emit dirty state.
+ * if not, flush.
  * \param r300          The context.
  * \param flags         See r300_prepare_flags.
- * \param index_buffer  The index buffer to validate. The parameter may be NULL.
  * \param cs_dwords     The number of dwords to reserve in CS.
- * \param aos_offset    The offset passed to emit_aos.
- * \param index_bias    The index bias to emit.
+ * \return TRUE if the CS was flushed
  */
-static boolean r300_prepare_for_rendering(struct r300_context *r300,
-                                          enum r300_prepare_flags flags,
-                                          struct pipe_resource *index_buffer,
-                                          unsigned cs_dwords,
-                                          int aos_offset,
-                                          int index_bias)
+static boolean r300_reserve_cs_dwords(struct r300_context *r300,
+                                   enum r300_prepare_flags flags,
+                                   unsigned cs_dwords)
 {
     boolean flushed        = FALSE;
     boolean first_draw     = flags & PREP_FIRST_DRAW;
     boolean emit_aos       = flags & PREP_EMIT_AOS;
     boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL;
-    boolean indexed        = flags & PREP_INDEXED;
     boolean hw_index_bias  = r500_index_bias_supported(r300);
 
     /* Add dirty state, index offset, and AOS. */
@@ -223,8 +217,32 @@ static boolean r300_prepare_for_rendering(struct r300_context *r300,
         flushed = TRUE;
     }
 
+    return flushed;
+}
+
+/**
+ * Validate buffers and emit dirty state.
+ * \param r300          The context.
+ * \param flags         See r300_prepare_flags.
+ * \param index_buffer  The index buffer to validate. The parameter may be NULL.
+ * \param aos_offset    The offset passed to emit_aos.
+ * \param index_bias    The index bias to emit.
+ * \return TRUE if rendering should be skipped
+ */
+static boolean r300_emit_states(struct r300_context *r300,
+                                enum r300_prepare_flags flags,
+                                struct pipe_resource *index_buffer,
+                                int aos_offset,
+                                int index_bias)
+{
+    boolean first_draw     = flags & PREP_FIRST_DRAW;
+    boolean emit_aos       = flags & PREP_EMIT_AOS;
+    boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL;
+    boolean indexed        = flags & PREP_INDEXED;
+    boolean hw_index_bias  = r500_index_bias_supported(r300);
+
     /* Validate buffers and emit dirty state if needed. */
-    if (first_draw || flushed) {
+    if (first_draw) {
         if (!r300_emit_buffer_validate(r300, flags & PREP_VALIDATE_VBOS,
                                        index_buffer)) {
             fprintf(stderr, "r300: CS space validation failed. "
@@ -250,6 +268,30 @@ static boolean r300_prepare_for_rendering(struct r300_context *r300,
     return TRUE;
 }
 
+/**
+ * Check if the requested number of dwords is available in the CS and
+ * if not, flush. Then validate buffers and emit dirty state.
+ * \param r300          The context.
+ * \param flags         See r300_prepare_flags.
+ * \param index_buffer  The index buffer to validate. The parameter may be NULL.
+ * \param cs_dwords     The number of dwords to reserve in CS.
+ * \param aos_offset    The offset passed to emit_aos.
+ * \param index_bias    The index bias to emit.
+ * \return TRUE if rendering should be skipped
+ */
+static boolean r300_prepare_for_rendering(struct r300_context *r300,
+                                          enum r300_prepare_flags flags,
+                                          struct pipe_resource *index_buffer,
+                                          unsigned cs_dwords,
+                                          int aos_offset,
+                                          int index_bias)
+{
+    if (r300_reserve_cs_dwords(r300, flags, cs_dwords))
+        flags |= PREP_FIRST_DRAW;
+
+    return r300_emit_states(r300, flags, index_buffer, aos_offset, index_bias);
+}
+
 static boolean immd_is_good_idea(struct r300_context *r300,
                                  unsigned count)
 {
@@ -675,7 +717,8 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe,
     struct pipe_transfer *ib_transfer = NULL;
     unsigned count = info->count;
     int i;
-    void* indices = NULL;
+    void *indices = NULL;
+    boolean indexed = info->indexed && r300->index_buffer.buffer;
 
     if (r300->skip_rendering) {
         return;
@@ -687,6 +730,11 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe,
 
     r300_update_derived_state(r300);
 
+    r300_reserve_cs_dwords(r300,
+            PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL |
+            (indexed ? PREP_INDEXED : 0),
+            indexed ? 256 : 6);
+
     for (i = 0; i < r300->vertex_buffer_count; i++) {
         if (r300->vertex_buffer[i].buffer) {
             void *buf = pipe_buffer_map(pipe,
@@ -697,14 +745,16 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe,
         }
     }
 
-    if (info->indexed && r300->index_buffer.buffer) {
+    if (indexed) {
         indices = pipe_buffer_map(pipe, r300->index_buffer.buffer,
                                   PIPE_TRANSFER_READ, &ib_transfer);
     }
 
     draw_set_mapped_index_buffer(r300->draw, indices);
 
+    r300->draw_vbo_locked = TRUE;
     draw_vbo(r300->draw, info);
+    r300->draw_vbo_locked = FALSE;
 
     /* XXX Not sure whether this is the best fix.
      * It prevents CS from being rejected and weird assertion failures. */
@@ -718,7 +768,7 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe,
         }
     }
 
-    if (ib_transfer) {
+    if (indexed) {
         pipe_buffer_unmap(pipe, r300->index_buffer.buffer, ib_transfer);
         draw_set_mapped_index_buffer(r300->draw, NULL);
     }
@@ -738,7 +788,6 @@ struct r300_render {
     unsigned hwprim;
 
     /* VBO */
-    size_t vbo_offset;
     size_t vbo_max_used;
     void * vbo_ptr;
 
@@ -769,18 +818,19 @@ static boolean r300_render_allocate_vertices(struct vbuf_render* render,
     struct pipe_screen* screen = r300->context.screen;
     size_t size = (size_t)vertex_size * (size_t)count;
 
-    if (size + r300render->vbo_offset > r300->draw_vbo_size)
+    DBG(r300, DBG_DRAW, "r300: render_allocate_vertices (size: %d)\n", size);
+
+    if (size + r300->draw_vbo_offset > r300->draw_vbo_size)
     {
 	pipe_resource_reference(&r300->vbo, NULL);
         r300->vbo = pipe_buffer_create(screen,
 				       PIPE_BIND_VERTEX_BUFFER,
 				       R300_MAX_DRAW_VBO_SIZE);
-        r300render->vbo_offset = 0;
+        r300->draw_vbo_offset = 0;
         r300->draw_vbo_size = R300_MAX_DRAW_VBO_SIZE;
     }
 
     r300render->vertex_size = vertex_size;
-    r300->vbo_offset = r300render->vbo_offset;
 
     return (r300->vbo) ? TRUE : FALSE;
 }
@@ -792,6 +842,8 @@ static void* r300_render_map_vertices(struct vbuf_render* render)
 
     assert(!r300render->vbo_transfer);
 
+    DBG(r300, DBG_DRAW, "r300: render_map_vertices\n");
+
     r300render->vbo_ptr = pipe_buffer_map(&r300render->r300->context,
 					  r300->vbo,
                                           PIPE_TRANSFER_WRITE,
@@ -799,7 +851,7 @@ static void* r300_render_map_vertices(struct vbuf_render* render)
 
     assert(r300render->vbo_ptr);
 
-    return ((uint8_t*)r300render->vbo_ptr + r300render->vbo_offset);
+    return ((uint8_t*)r300render->vbo_ptr + r300->draw_vbo_offset);
 }
 
 static void r300_render_unmap_vertices(struct vbuf_render* render,
@@ -812,6 +864,8 @@ static void r300_render_unmap_vertices(struct vbuf_render* render,
 
     assert(r300render->vbo_transfer);
 
+    DBG(r300, DBG_DRAW, "r300: render_unmap_vertices\n");
+
     r300render->vbo_max_used = MAX2(r300render->vbo_max_used,
                                     r300render->vertex_size * (max + 1));
     pipe_buffer_unmap(context, r300->vbo, r300render->vbo_transfer);
@@ -822,8 +876,11 @@ static void r300_render_unmap_vertices(struct vbuf_render* render,
 static void r300_render_release_vertices(struct vbuf_render* render)
 {
     struct r300_render* r300render = r300_render(render);
+    struct r300_context* r300 = r300render->r300;
 
-    r300render->vbo_offset += r300render->vbo_max_used;
+    DBG(r300, DBG_DRAW, "r300: render_release_vertices\n");
+
+    r300->draw_vbo_offset += r300render->vbo_max_used;
     r300render->vbo_max_used = 0;
 }
 
@@ -851,13 +908,13 @@ static void r300_render_draw_arrays(struct vbuf_render* render,
     CS_LOCALS(r300);
     (void) i; (void) ptr;
 
-    if (!r300_prepare_for_rendering(r300,
-                                    PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL,
-                                    NULL, dwords, 0, 0))
-        return;
-
     DBG(r300, DBG_DRAW, "r300: render_draw_arrays (count: %d)\n", count);
 
+    if (!r300_emit_states(r300,
+            PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL,
+            NULL, 0, 0))
+        return;
+
     /* Uncomment to dump all VBOs rendered through this interface.
      * Slow and noisy!
     ptr = pipe_buffer_map(&r300render->r300->context,
@@ -893,7 +950,7 @@ static void r300_render_draw_elements(struct vbuf_render* render,
     struct r300_context* r300 = r300render->r300;
     int i;
     unsigned end_cs_dwords;
-    unsigned max_index = (r300->draw_vbo_size - r300render->vbo_offset) /
+    unsigned max_index = (r300->draw_vbo_size - r300->draw_vbo_offset) /
                          (r300render->r300->vertex_info.size * 4) - 1;
     unsigned short_count;
     unsigned free_dwords;
@@ -901,15 +958,14 @@ static void r300_render_draw_elements(struct vbuf_render* render,
     CS_LOCALS(r300);
     DBG(r300, DBG_DRAW, "r300: render_draw_elements (count: %d)\n", count);
 
-    /* Reserve at least 256 dwords.
-     *
-     * Below we manage the CS space manually because there may be more
-     * indices than it can fit in CS. */
-    if (!r300_prepare_for_rendering(r300,
+    if (!r300_emit_states(r300,
             PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL | PREP_INDEXED,
-            NULL, 256, 0, 0))
+            NULL, 0, 0))
         return;
 
+    /* Below we manage the CS space manually because there may be more
+     * indices than it can fit in CS. */
+
     end_cs_dwords = r300_get_num_cs_end_dwords(r300);
 
     while (count) {
@@ -973,8 +1029,6 @@ static struct vbuf_render* r300_render_create(struct r300_context* r300)
     r300render->base.release_vertices = r300_render_release_vertices;
     r300render->base.destroy = r300_render_destroy;
 
-    r300render->vbo_offset = 0;
-
     return &r300render->base;
 }
 




More information about the mesa-commit mailing list