r300g: Massively cleanup OQ.
authorCorbin Simpson <MostAwesomeDude@gmail.com>
Wed, 19 Aug 2009 00:52:03 +0000 (17:52 -0700)
committerCorbin Simpson <MostAwesomeDude@gmail.com>
Wed, 19 Aug 2009 04:25:53 +0000 (21:25 -0700)
Still broken, but compiles cleaner, behaves better, etc.

src/gallium/drivers/r300/r300_context.c
src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_query.c
src/gallium/drivers/r300/r300_query.h
src/gallium/drivers/r300/r300_reg.h

index c8510bc63e4391793d6243e9eefe1c14526e4acb..da67bc29b89888504a9af244961b48581ec10f6c 100644 (file)
@@ -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);
 
index fc8a4498933a4a6af7330f7fa576a3f25a97fd34..f78492d4aa997e0c974f6b3be2621abb837b84da 100644 (file)
 
 #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;
index 53256fc6dd36844ddf9b36877811894da311e5b5..bd4d59e6f1ad6097e0863ac2b97d35e16f43a3cf 100644 (file)
@@ -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,
index 8fc61c2dec71fdca056b2d2d7c085f4973c91cf6..b3a8dc12c8d655cafe1eafb1d89815cc3ae4493e 100644 (file)
 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;
     }
index 6a7646087a74bb5fbc821116591d570068673016..4f50e8f84401599ddd5ae9b89ffe92219089287d 100644 (file)
 
 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;
index 6825d9987001b49f5da23774bc8bb5b1671d000d..03cd219cde91ace20ac4eeb8e16a223511bc892b 100644 (file)
@@ -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* */