Mesa (master): r300g: Massively cleanup OQ.

Corbin Simpson csimpson at kemper.freedesktop.org
Wed Aug 19 04:28:59 UTC 2009


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

Author: Corbin Simpson <MostAwesomeDude at gmail.com>
Date:   Tue Aug 18 17:52:03 2009 -0700

r300g: Massively cleanup OQ.

Still broken, but compiles cleaner, behaves better, etc.

---

 src/gallium/drivers/r300/r300_context.c |   24 ++++++++--
 src/gallium/drivers/r300/r300_context.h |   32 ++++++++++++
 src/gallium/drivers/r300/r300_emit.c    |   79 +++++++++++++++++++++++++++++++
 src/gallium/drivers/r300/r300_query.c   |   57 +++++++++++++++-------
 src/gallium/drivers/r300/r300_query.h   |    7 ---
 src/gallium/drivers/r300/r300_reg.h     |    4 ++
 6 files changed, 174 insertions(+), 29 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c
index c8510bc..da67bc2 100644
--- a/src/gallium/drivers/r300/r300_context.c
+++ b/src/gallium/drivers/r300/r300_context.c
@@ -88,9 +88,21 @@ static boolean r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
 
 static void r300_destroy_context(struct pipe_context* context) {
     struct r300_context* r300 = r300_context(context);
+    struct r300_query* query, * temp;
 
     draw_destroy(r300->draw);
 
+    /* Free the OQ BO. */
+    context->screen->buffer_destroy(r300->oqbo);
+
+    /* If there are any queries pending or not destroyed, remove them now. */
+    if (r300->query_list) {
+        foreach_s(query, temp, r300->query_list) {
+            remove_from_list(query);
+            FREE(query);
+        }
+    }
+
     FREE(r300->blend_color_state);
     FREE(r300->rs_block);
     FREE(r300->scissor_state);
@@ -145,6 +157,11 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,
     r300->context.is_texture_referenced = r300_is_texture_referenced;
     r300->context.is_buffer_referenced = r300_is_buffer_referenced;
 
+    r300->blend_color_state = CALLOC_STRUCT(r300_blend_color_state);
+    r300->rs_block = CALLOC_STRUCT(r300_rs_block);
+    r300->scissor_state = CALLOC_STRUCT(r300_scissor_state);
+    r300->viewport_state = CALLOC_STRUCT(r300_viewport_state);
+
     /* Create a Draw. This is used for vert collation and SW TCL. */
     r300->draw = draw_create();
     /* Enable our renderer. */
@@ -155,10 +172,9 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,
      * transform in hardware, always. */
     draw_set_viewport_state(r300->draw, &r300_viewport_identity);
 
-    r300->blend_color_state = CALLOC_STRUCT(r300_blend_color_state);
-    r300->rs_block = CALLOC_STRUCT(r300_rs_block);
-    r300->scissor_state = CALLOC_STRUCT(r300_scissor_state);
-    r300->viewport_state = CALLOC_STRUCT(r300_viewport_state);
+    /* Open up the OQ BO. */
+    r300->oqbo = screen->buffer_create(screen, 4096,
+            PIPE_BUFFER_USAGE_VERTEX, 4096);
 
     r300_init_flush_functions(r300);
 
diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index fc8a449..f78492d 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -25,9 +25,13 @@
 
 #include "draw/draw_context.h"
 #include "draw/draw_vertex.h"
+
 #include "pipe/p_context.h"
+
 #include "tgsi/tgsi_scan.h"
+
 #include "util/u_memory.h"
+#include "util/u_simple_list.h"
 
 #include "r300_clear.h"
 #include "r300_query.h"
@@ -150,6 +154,29 @@ struct r300_constant_buffer {
     unsigned count;
 };
 
+/* Query object.
+ *
+ * This is not a subclass of pipe_query because pipe_query is never
+ * actually fully defined. So, rather than have it as a member, and do
+ * subclass-style casting, we treat pipe_query as an opaque, and just
+ * trust that our state tracker does not ever mess up query objects.
+ */
+struct r300_query {
+    /* The kind of query. Currently only OQ is supported. */
+    unsigned type;
+    /* Whether this query is currently active. Only active queries will
+     * get emitted into the command stream, and only active queries get
+     * tallied. */
+    boolean active;
+    /* The current count of this query. Required to be at least 32 bits. */
+    unsigned int count;
+    /* The offset of this query into the query buffer, in bytes. */
+    unsigned offset;
+    /* Linked list members. */
+    struct r300_query* prev;
+    struct r300_query* next;
+};
+
 struct r300_texture {
     /* Parent class */
     struct pipe_texture tex;
@@ -203,6 +230,11 @@ struct r300_context {
     /* Offset into the VBO. */
     size_t vbo_offset;
 
+    /* Occlusion query buffer. */
+    struct pipe_buffer* oqbo;
+    /* Query list. */
+    struct r300_query* query_list;
+
     /* Various CSO state objects. */
     /* Blend state. */
     struct r300_blend_state* blend_state;
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index 53256fc..bd4d59e 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -319,6 +319,79 @@ void r300_emit_fb_state(struct r300_context* r300,
     END_CS;
 }
 
+void r300_emit_query_begin(struct r300_context* r300,
+                           struct r300_query* query)
+{
+    CS_LOCALS(r300);
+
+    /* XXX This will almost certainly not return good results
+     * for overlapping queries. */
+    BEGIN_CS(2);
+    OUT_CS_REG(R300_ZB_ZPASS_DATA, 0);
+    END_CS;
+}
+
+void r300_emit_query_end(struct r300_context* r300,
+                         struct r300_query* query)
+{
+    struct r300_capabilities* caps = r300_screen(r300->context.screen)->caps;
+    CS_LOCALS(r300);
+
+    if (!r300->winsys->add_buffer(r300->winsys, r300->oqbo,
+                0, RADEON_GEM_DOMAIN_GTT)) {
+        debug_printf("r300: There wasn't room for the OQ buffer!?"
+                " Oh noes!\n");
+    }
+
+    assert(caps->num_frag_pipes);
+    BEGIN_CS(6 * caps->num_frag_pipes + 2);
+    /* I'm not so sure I like this switch, but it's hard to be elegant
+     * when there's so many special cases...
+     *
+     * So here's the basic idea. For each pipe, enable writes to it only,
+     * then put out the relocation for ZPASS_ADDR, taking into account a
+     * 4-byte offset for each pipe. RV380 and older are special; they have
+     * only two pipes, and the second pipe's enable is on bit 3, not bit 1,
+     * so there's a chipset cap for that. */
+    switch (caps->num_frag_pipes) {
+        case 4:
+            /* pipe 3 only */
+            OUT_CS_REG(R300_SU_REG_DEST, 1 << 3);
+            OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1);
+            OUT_CS_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 3),
+                    0, RADEON_GEM_DOMAIN_GTT, 0);
+        case 3:
+            /* pipe 2 only */
+            OUT_CS_REG(R300_SU_REG_DEST, 1 << 2);
+            OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1);
+            OUT_CS_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 2),
+                    0, RADEON_GEM_DOMAIN_GTT, 0);
+        case 2:
+            /* pipe 1 only */
+            /* As mentioned above, accomodate RV380 and older. */
+            OUT_CS_REG(R300_SU_REG_DEST,
+                    1 << (caps->high_second_pipe ? 3 : 1));
+            OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1);
+            OUT_CS_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 1),
+                    0, RADEON_GEM_DOMAIN_GTT, 0);
+        case 1:
+            /* pipe 0 only */
+            OUT_CS_REG(R300_SU_REG_DEST, 1 << 0);
+            OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1);
+            OUT_CS_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 0),
+                    0, RADEON_GEM_DOMAIN_GTT, 0);
+        default:
+            debug_printf("r300: Implementation error: Chipset reports %d"
+                    " pixel pipes!\n", caps->num_frag_pipes);
+            assert(0);
+    }
+
+    /* And, finally, reset it to normal... */
+    OUT_CS_REG(R300_SU_REG_DEST, 0xF);
+    END_CS;
+
+}
+
 void r300_emit_rs_state(struct r300_context* r300, struct r300_rs_state* rs)
 {
     CS_LOCALS(r300);
@@ -615,6 +688,12 @@ validate:
             goto validate;
         }
     }
+    /* ...occlusion query buffer... */
+    if (!r300->winsys->add_buffer(r300->winsys, r300->oqbo,
+                0, RADEON_GEM_DOMAIN_GTT)) {
+        r300->context.flush(&r300->context, 0, NULL);
+        goto validate;
+    }
     /* ...and vertex buffer. */
     if (r300->vbo) {
         if (!r300->winsys->add_buffer(r300->winsys, r300->vbo,
diff --git a/src/gallium/drivers/r300/r300_query.c b/src/gallium/drivers/r300/r300_query.c
index 8fc61c2..b3a8dc1 100644
--- a/src/gallium/drivers/r300/r300_query.c
+++ b/src/gallium/drivers/r300/r300_query.c
@@ -25,14 +25,30 @@
 static struct pipe_query* r300_create_query(struct pipe_context* pipe,
                                             unsigned query_type)
 {
-    struct r300_query* q = CALLOC_STRUCT(r300_query);
+    struct r300_context* r300 = r300_context(pipe);
+    struct r300_screen* r300screen = r300_screen(r300->context.screen);
+    unsigned query_size = r300screen->caps->num_frag_pipes * 4;
+    struct r300_query* q, * qptr;
+
+    q = CALLOC_STRUCT(r300_query);
 
     q->type = query_type;
     assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
 
-    /* XXX this is to force winsys to give us a GTT buffer */
-    q->buf = pipe->screen->buffer_create(pipe->screen, 64,
-            PIPE_BUFFER_USAGE_VERTEX, 64);
+    q->active = FALSE;
+
+    if (!r300->query_list) {
+        r300->query_list = q;
+    } else if (!is_empty_list(r300->query_list)) {
+        qptr = last_elem(r300->query_list);
+        q->offset = qptr->offset + query_size;
+        insert_at_tail(r300->query_list, q);
+    }
+
+    /* XXX */
+    if (q->offset >= 4096) {
+        q->offset = 0;
+    }
 
     return (struct pipe_query*)q;
 }
@@ -40,6 +56,9 @@ static struct pipe_query* r300_create_query(struct pipe_context* pipe,
 static void r300_destroy_query(struct pipe_context* pipe,
                                struct pipe_query* query)
 {
+    struct r300_query* q = (struct r300_query*)query;
+
+    remove_from_list(q);
     FREE(query);
 }
 
@@ -49,15 +68,15 @@ static void r300_begin_query(struct pipe_context* pipe,
     uint32_t* map;
     struct r300_context* r300 = r300_context(pipe);
     struct r300_query* q = (struct r300_query*)query;
-    CS_LOCALS(r300);
 
-    map = pipe_buffer_map(pipe->screen, q->buf, PIPE_BUFFER_USAGE_CPU_WRITE);
+    map = pipe->screen->buffer_map(pipe->screen, r300->oqbo,
+            PIPE_BUFFER_USAGE_CPU_WRITE);
+    map += q->offset / 4;
     *map = ~0;
-    pipe_buffer_unmap(pipe->screen, q->buf);
+    pipe->screen->buffer_unmap(pipe->screen, r300->oqbo);
 
-    BEGIN_CS(2);
-    OUT_CS_REG(R300_ZB_ZPASS_DATA, 0);
-    END_CS;
+    r300_emit_dirty_state(r300);
+    r300_emit_query_begin(r300, q);
 }
 
 static void r300_end_query(struct pipe_context* pipe,
@@ -65,12 +84,9 @@ static void r300_end_query(struct pipe_context* pipe,
 {
     struct r300_context* r300 = r300_context(pipe);
     struct r300_query* q = (struct r300_query*)query;
-    CS_LOCALS(r300);
 
-    BEGIN_CS(4);
-    OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1);
-    OUT_CS_RELOC(q->buf, 0, 0, RADEON_GEM_DOMAIN_GTT, 0);
-    END_CS;
+    r300_emit_dirty_state(r300);
+    r300_emit_query_end(r300, q);
 }
 
 static boolean r300_get_query_result(struct pipe_context* pipe,
@@ -78,6 +94,7 @@ static boolean r300_get_query_result(struct pipe_context* pipe,
                                      boolean wait,
                                      uint64_t* result)
 {
+    struct r300_context* r300 = r300_context(pipe);
     struct r300_query* q = (struct r300_query*)query;
     uint32_t* map;
     uint32_t temp;
@@ -89,11 +106,15 @@ static boolean r300_get_query_result(struct pipe_context* pipe,
         pipe->flush(pipe, 0, NULL);
     }
 
-    map = pipe_buffer_map(pipe->screen, q->buf, PIPE_BUFFER_USAGE_CPU_READ);
+
+    map = pipe->screen->buffer_map(pipe->screen, r300->oqbo,
+            PIPE_BUFFER_USAGE_CPU_WRITE);
+    map += q->offset / 4;
     temp = *map;
-    pipe_buffer_unmap(pipe->screen, q->buf);
+    *map = ~0;
+    pipe->screen->buffer_unmap(pipe->screen, r300->oqbo);
 
-    if (temp < 0) {
+    if (temp == ~0) {
         /* Our results haven't been written yet... */
         return FALSE;
     }
diff --git a/src/gallium/drivers/r300/r300_query.h b/src/gallium/drivers/r300/r300_query.h
index 6a76460..4f50e8f 100644
--- a/src/gallium/drivers/r300/r300_query.h
+++ b/src/gallium/drivers/r300/r300_query.h
@@ -29,13 +29,6 @@
 
 struct r300_context;
 
-struct r300_query {
-    /* The kind of query. Currently only OQ is supported. */
-    unsigned type;
-    /* Buffer object where we want our results to reside. */
-    struct pipe_buffer* buf;
-};
-
 static INLINE struct r300_query* r300_query(struct pipe_query* q)
 {
     return (struct r300_query*)q;
diff --git a/src/gallium/drivers/r300/r300_reg.h b/src/gallium/drivers/r300/r300_reg.h
index 6825d99..03cd219 100644
--- a/src/gallium/drivers/r300/r300_reg.h
+++ b/src/gallium/drivers/r300/r300_reg.h
@@ -3312,6 +3312,10 @@ enum {
 
 #define R200_3D_DRAW_IMMD_2      0xC0003500
 
+/* XXX Oh look, stuff not brought over from docs yet */
+
+#define R300_SU_REG_DEST                    0x42C8
+
 #endif /* _R300_REG_H */
 
 /* *INDENT-ON* */




More information about the mesa-commit mailing list