r600g: add a new simple API for state emission
authorMarek Olšák <maraeo@gmail.com>
Mon, 30 Jan 2012 00:23:14 +0000 (01:23 +0100)
committerMarek Olšák <maraeo@gmail.com>
Tue, 31 Jan 2012 22:12:30 +0000 (23:12 +0100)
src/gallium/drivers/r600/r600_hw_context.c
src/gallium/drivers/r600/r600_pipe.c
src/gallium/drivers/r600/r600_pipe.h
src/gallium/drivers/r600/r600_state_common.c

index aa01d0d..3399466 100644 (file)
@@ -931,11 +931,17 @@ out_err:
 void r600_need_cs_space(struct r600_context *ctx, unsigned num_dw,
                        boolean count_draw_in)
 {
+       struct r600_atom *state;
+
        /* The number of dwords we already used in the CS so far. */
        num_dw += ctx->cs->cdw;
 
        if (count_draw_in) {
                /* The number of dwords all the dirty states would take. */
+               LIST_FOR_EACH_ENTRY(state, &ctx->dirty_states, head) {
+                       num_dw += state->num_dw;
+               }
+
                num_dw += ctx->pm4_dirty_cdwords;
 
                /* The upper-bound of how much a draw command would take. */
index bd68eff..b927625 100644 (file)
@@ -282,6 +282,8 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void
                return NULL;
        }
 
+       LIST_INITHEAD(&rctx->dirty_states);
+
        r600_get_backend_mask(rctx); /* this emits commands and must be last */
 
        return &rctx->context;
index 0aaec4b..78b6d83 100644 (file)
 #define R600_BIG_ENDIAN 0
 #endif
 
+enum r600_atom_flags {
+       /* When set, atoms are added at the beginning of the dirty list
+        * instead of the end. */
+       EMIT_EARLY = (1 << 0)
+};
+
+/* This encapsulates a state or an operation which can emitted into the GPU
+ * command stream. It's not limited to states only, it can be used for anything
+ * that wants to write commands into the CS (e.g. cache flushes). */
+struct r600_atom {
+       void (*emit)(struct r600_context *ctx, struct r600_atom *state);
+
+       unsigned                num_dw;
+       enum r600_atom_flags    flags;
+       bool                    dirty;
+
+       struct list_head        head;
+};
+
 enum r600_pipe_state_id {
        R600_PIPE_STATE_BLEND = 0,
        R600_PIPE_STATE_BLEND_COLOR,
@@ -251,6 +270,9 @@ struct r600_context {
 
        unsigned default_ps_gprs, default_vs_gprs;
 
+       /* States based on r600_state. */
+       struct list_head                dirty_states;
+
        /* Below are variables from the old r600_context.
         */
        struct radeon_winsys_cs *cs;
@@ -290,6 +312,26 @@ struct r600_context {
        unsigned                *vs_so_stride_in_dw;
 };
 
+static INLINE void r600_emit_atom(struct r600_context *rctx, struct r600_atom *atom)
+{
+       atom->emit(rctx, atom);
+       atom->dirty = false;
+       if (atom->head.next && atom->head.prev)
+               LIST_DELINIT(&atom->head);
+}
+
+static INLINE void r600_atom_dirty(struct r600_context *rctx, struct r600_atom *state)
+{
+       if (!state->dirty) {
+               if (state->flags & EMIT_EARLY) {
+                       LIST_ADD(&state->head, &rctx->dirty_states);
+               } else {
+                       LIST_ADDTAIL(&state->head, &rctx->dirty_states);
+               }
+               state->dirty = true;
+       }
+}
+
 /* evergreen_state.c */
 void evergreen_init_state_functions(struct r600_context *rctx);
 void evergreen_init_config(struct r600_context *rctx);
index c3a8e3d..0c06ad0 100644 (file)
@@ -671,6 +671,7 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *dinfo)
        struct pipe_index_buffer ib = {};
        unsigned prim, mask, ls_mask = 0;
        struct r600_block *dirty_block = NULL, *next_block = NULL;
+       struct r600_atom *state = NULL, *next_state = NULL;
 
        if ((!info.count && (info.indexed || !info.count_from_stream_output)) ||
            (info.indexed && !rctx->vbuf_mgr->index_buffer.buffer) ||
@@ -788,6 +789,9 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *dinfo)
        /* Emit states. */
        r600_need_cs_space(rctx, 0, TRUE);
 
+       LIST_FOR_EACH_ENTRY_SAFE(state, next_state, &rctx->dirty_states, head) {
+               r600_emit_atom(rctx, state);
+       }
        LIST_FOR_EACH_ENTRY_SAFE(dirty_block, next_block, &rctx->dirty,list) {
                r600_context_block_emit_dirty(rctx, dirty_block);
        }