r300g: decouple drawing code and two-sided stencil refvalue fallback
authorMarek Olšák <maraeo@gmail.com>
Wed, 26 May 2010 21:47:27 +0000 (23:47 +0200)
committerMarek Olšák <maraeo@gmail.com>
Wed, 26 May 2010 22:08:42 +0000 (00:08 +0200)
It's now more separate from the rest of the driver and it can be disabled
by commenting out just 1 line. Well, I couldn't make the previous version
work with SW TCL reliably, that's the reason of this little rework.

src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_render.c
src/gallium/drivers/r300/r300_state.c

index 97b69e76527acdd39bdc98e34c741a1b8552abdc..e047307e10bb8aff6de9452c2505f7a215c1f805 100644 (file)
@@ -36,9 +36,9 @@
 
 struct u_upload_mgr;
 struct r300_context;
-
 struct r300_fragment_shader;
 struct r300_vertex_shader;
+struct r300_stencilref_context;
 
 struct r300_atom {
     /* List pointers. */
@@ -86,7 +86,7 @@ struct r300_dsa_state {
     /* Whether a two-sided stencil is enabled. */
     boolean two_sided;
     /* Whether a fallback should be used for a two-sided stencil ref value. */
-    boolean stencil_ref_bf_fallback;
+    boolean two_sided_stencil_ref;
 };
 
 struct r300_rs_state {
@@ -331,21 +331,6 @@ struct r300_context {
     /* Parent class */
     struct pipe_context context;
 
-    /* Emission of drawing packets. */
-    void (*emit_draw_arrays_immediate)(
-            struct r300_context *r300,
-            unsigned mode, unsigned start, unsigned count);
-
-    void (*emit_draw_arrays)(
-            struct r300_context *r300,
-            unsigned mode, unsigned count);
-
-    void (*emit_draw_elements)(
-            struct r300_context *r300, struct pipe_resource* indexBuffer,
-            unsigned indexSize, unsigned minIndex, unsigned maxIndex,
-            unsigned mode, unsigned start, unsigned count);
-
-
     /* The interface to the windowing system, etc. */
     struct r300_winsys_screen *rws;
     /* Screen. */
@@ -354,6 +339,8 @@ struct r300_context {
     struct draw_context* draw;
     /* Accelerated blit support. */
     struct blitter_context* blitter;
+    /* Stencil two-sided reference value fallback. */
+    struct r300_stencilref_context *stencilref_fallback;
 
     /* Vertex buffer for rendering. */
     struct pipe_resource* vbo;
@@ -441,9 +428,6 @@ struct r300_context {
     uint32_t zbuffer_bpp;
     /* Whether rendering is conditional and should be skipped. */
     boolean skip_rendering;
-    /* Whether the two-sided stencil ref value is different for front and
-     * back faces, and fallback should be used for r3xx-r4xx. */
-    boolean stencil_ref_bf_fallback;
     /* Point sprites texcoord index,  1 bit per texcoord */
     int sprite_coord_enable;
     /* Whether two-sided color selection is enabled (AKA light_twoside). */
index c289c3d0e5ddaf068a3dfa2830e31c505e2ce9dc..cad78a13907c4d2bdfc6dca19654841b4c47648c 100644 (file)
@@ -157,11 +157,6 @@ static void r300_prepare_for_rendering(struct r300_context *r300,
     boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL;
     unsigned end_dwords = 0;
 
-    /* Stencil ref fallback. */
-    if (r300->stencil_ref_bf_fallback) {
-        cs_dwords = cs_dwords * 2 + 10;
-    }
-
     /* Add dirty state, index offset, and AOS. */
     if (first_draw) {
         cs_dwords += r300_get_num_dirty_dwords(r300);
@@ -250,7 +245,7 @@ static boolean immd_is_good_idea(struct r300_context *r300,
  * after resolving fallback issues (e.g. stencil ref two-sided).             *
  ****************************************************************************/
 
-static void r500_emit_draw_arrays_immediate(struct r300_context *r300,
+static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
                                             unsigned mode,
                                             unsigned start,
                                             unsigned count)
@@ -340,7 +335,7 @@ static void r500_emit_draw_arrays_immediate(struct r300_context *r300,
     }
 }
 
-static void r500_emit_draw_arrays(struct r300_context *r300,
+static void r300_emit_draw_arrays(struct r300_context *r300,
                                   unsigned mode,
                                   unsigned count)
 {
@@ -369,7 +364,7 @@ static void r500_emit_draw_arrays(struct r300_context *r300,
     END_CS;
 }
 
-static void r500_emit_draw_elements(struct r300_context *r300,
+static void r300_emit_draw_elements(struct r300_context *r300,
                                     struct pipe_resource* indexBuffer,
                                     unsigned indexSize,
                                     unsigned minIndex,
@@ -432,104 +427,6 @@ static void r500_emit_draw_elements(struct r300_context *r300,
     END_CS;
 }
 
-/*****************************************************************************
- * The emission of draw packets for r300 which take care of the two-sided    *
- * stencil ref fallback and call r500's functions.                           *
- ****************************************************************************/
-
-/* Set drawing for front faces. */
-static void r300_begin_stencil_ref_fallback(struct r300_context *r300)
-{
-    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
-    CS_LOCALS(r300);
-
-    BEGIN_CS(2);
-    OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode | R300_CULL_BACK);
-    END_CS;
-}
-
-/* Set drawing for back faces. */
-static void r300_switch_stencil_ref_side(struct r300_context *r300)
-{
-    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
-    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
-    CS_LOCALS(r300);
-
-    BEGIN_CS(4);
-    OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode | R300_CULL_FRONT);
-    OUT_CS_REG(R300_ZB_STENCILREFMASK,
-               dsa->stencil_ref_bf | r300->stencil_ref.ref_value[1]);
-    END_CS;
-}
-
-/* Restore the original state. */
-static void r300_end_stencil_ref_fallback(struct r300_context *r300)
-{
-    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
-    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
-    CS_LOCALS(r300);
-
-    BEGIN_CS(4);
-    OUT_CS_REG(R300_SU_CULL_MODE, rs->cull_mode);
-    OUT_CS_REG(R300_ZB_STENCILREFMASK,
-               dsa->stencil_ref_mask | r300->stencil_ref.ref_value[0]);
-    END_CS;
-}
-
-static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
-                                            unsigned mode,
-                                            unsigned start,
-                                            unsigned count)
-{
-    if (!r300->stencil_ref_bf_fallback) {
-        r500_emit_draw_arrays_immediate(r300, mode, start, count);
-    } else {
-        r300_begin_stencil_ref_fallback(r300);
-        r500_emit_draw_arrays_immediate(r300, mode, start, count);
-        r300_switch_stencil_ref_side(r300);
-        r500_emit_draw_arrays_immediate(r300, mode, start, count);
-        r300_end_stencil_ref_fallback(r300);
-    }
-}
-
-static void r300_emit_draw_arrays(struct r300_context *r300,
-                                  unsigned mode,
-                                  unsigned count)
-{
-    if (!r300->stencil_ref_bf_fallback) {
-        r500_emit_draw_arrays(r300, mode, count);
-    } else {
-        r300_begin_stencil_ref_fallback(r300);
-        r500_emit_draw_arrays(r300, mode, count);
-        r300_switch_stencil_ref_side(r300);
-        r500_emit_draw_arrays(r300, mode, count);
-        r300_end_stencil_ref_fallback(r300);
-    }
-}
-
-static void r300_emit_draw_elements(struct r300_context *r300,
-                                    struct pipe_resource* indexBuffer,
-                                    unsigned indexSize,
-                                    unsigned minIndex,
-                                    unsigned maxIndex,
-                                    unsigned mode,
-                                    unsigned start,
-                                    unsigned count)
-{
-    if (!r300->stencil_ref_bf_fallback) {
-        r500_emit_draw_elements(r300, indexBuffer, indexSize,
-                                minIndex, maxIndex, mode, start, count);
-    } else {
-        r300_begin_stencil_ref_fallback(r300);
-        r500_emit_draw_elements(r300, indexBuffer, indexSize,
-                                minIndex, maxIndex, mode, start, count);
-        r300_switch_stencil_ref_side(r300);
-        r500_emit_draw_elements(r300, indexBuffer, indexSize,
-                                minIndex, maxIndex, mode, start, count);
-        r300_end_stencil_ref_fallback(r300);
-    }
-}
-
 static void r300_shorten_ubyte_elts(struct r300_context* r300,
                                     struct pipe_resource** elts,
                                     unsigned start,
@@ -638,12 +535,12 @@ static void r300_draw_range_elements(struct pipe_context* pipe,
     u_upload_flush(r300->upload_vb);
     u_upload_flush(r300->upload_ib);
     if (alt_num_verts || count <= 65535) {
-        r300->emit_draw_elements(r300, indexBuffer, indexSize,
+        r300_emit_draw_elements(r300, indexBuffer, indexSize,
                                  minIndex, maxIndex, mode, start, count);
     } else {
         do {
             short_count = MIN2(count, 65534);
-            r300->emit_draw_elements(r300, indexBuffer, indexSize,
+            r300_emit_draw_elements(r300, indexBuffer, indexSize,
                                      minIndex, maxIndex,
                                      mode, start, short_count);
 
@@ -697,18 +594,18 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
     r300_update_derived_state(r300);
 
     if (immd_is_good_idea(r300, count)) {
-        r300->emit_draw_arrays_immediate(r300, mode, start, count);
+        r300_emit_draw_arrays_immediate(r300, mode, start, count);
     } else {
         /* 9 spare dwords for emit_draw_arrays. */
         r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS,
                                NULL, 9, start, 0, NULL);
 
         if (alt_num_verts || count <= 65535) {
-            r300->emit_draw_arrays(r300, mode, count);
+            r300_emit_draw_arrays(r300, mode, count);
         } else {
             do {
                 short_count = MIN2(count, 65535);
-                r300->emit_draw_arrays(r300, mode, short_count);
+                r300_emit_draw_arrays(r300, mode, short_count);
 
                 start += short_count;
                 count -= short_count;
@@ -945,7 +842,7 @@ static boolean r300_render_set_primitive(struct vbuf_render* render,
     return TRUE;
 }
 
-static void r500_render_draw_arrays(struct vbuf_render* render,
+static void r300_render_draw_arrays(struct vbuf_render* render,
                                     unsigned start,
                                     unsigned count)
 {
@@ -991,7 +888,7 @@ static void r500_render_draw_arrays(struct vbuf_render* render,
     END_CS;
 }
 
-static void r500_render_draw_elements(struct vbuf_render* render,
+static void r300_render_draw_elements(struct vbuf_render* render,
                                       const ushort* indices,
                                       uint count)
 {
@@ -1047,40 +944,6 @@ static void r500_render_draw_elements(struct vbuf_render* render,
     }
 }
 
-static void r300_render_draw_arrays(struct vbuf_render* render,
-                                    unsigned start,
-                                    unsigned count)
-{
-    struct r300_context* r300 = r300_render(render)->r300;
-
-    if (!r300->stencil_ref_bf_fallback) {
-        r500_render_draw_arrays(render, start, count);
-    } else {
-        r300_begin_stencil_ref_fallback(r300);
-        r500_render_draw_arrays(render, start, count);
-        r300_switch_stencil_ref_side(r300);
-        r500_render_draw_arrays(render, start, count);
-        r300_end_stencil_ref_fallback(r300);
-    }
-}
-
-static void r300_render_draw_elements(struct vbuf_render* render,
-                                      const ushort* indices,
-                                      uint count)
-{
-    struct r300_context* r300 = r300_render(render)->r300;
-
-    if (!r300->stencil_ref_bf_fallback) {
-        r500_render_draw_elements(render, indices, count);
-    } else {
-        r300_begin_stencil_ref_fallback(r300);
-        r500_render_draw_elements(render, indices, count);
-        r300_switch_stencil_ref_side(r300);
-        r500_render_draw_elements(render, indices, count);
-        r300_end_stencil_ref_fallback(r300);
-    }
-}
-
 static void r300_render_destroy(struct vbuf_render* render)
 {
     FREE(render);
@@ -1101,13 +964,8 @@ static struct vbuf_render* r300_render_create(struct r300_context* r300)
     r300render->base.map_vertices = r300_render_map_vertices;
     r300render->base.unmap_vertices = r300_render_unmap_vertices;
     r300render->base.set_primitive = r300_render_set_primitive;
-    if (r300->screen->caps.is_r500) {
-        r300render->base.draw_elements = r500_render_draw_elements;
-        r300render->base.draw_arrays = r500_render_draw_arrays;
-    } else {
-        r300render->base.draw_elements = r300_render_draw_elements;
-        r300render->base.draw_arrays = r300_render_draw_arrays;
-    }
+    r300render->base.draw_elements = r300_render_draw_elements;
+    r300render->base.draw_arrays = r300_render_draw_arrays;
     r300render->base.release_vertices = r300_render_release_vertices;
     r300render->base.destroy = r300_render_destroy;
 
@@ -1141,25 +999,150 @@ struct draw_stage* r300_draw_stage(struct r300_context* r300)
     return stage;
 }
 
+/****************************************************************************
+ * Two-sided stencil reference value fallback. It's designed to be as much
+ * separate from rest of the driver as possible.
+ ***************************************************************************/
+
+struct r300_stencilref_context {
+    void (*draw_arrays)(struct pipe_context *pipe,
+                        unsigned mode, unsigned start, unsigned count);
+
+    void (*draw_range_elements)(
+        struct pipe_context *pipe, struct pipe_resource *indexBuffer,
+        unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex,
+        unsigned mode, unsigned start, unsigned count);
+
+    uint32_t rs_cull_mode;
+    uint32_t zb_stencilrefmask;
+    ubyte ref_value_front;
+};
+
+static boolean r300_stencilref_needed(struct r300_context *r300)
+{
+    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
+
+    return dsa->two_sided_stencil_ref ||
+           (dsa->two_sided &&
+            r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]);
+}
+
+/* Set drawing for front faces. */
+static void r300_stencilref_begin(struct r300_context *r300)
+{
+    struct r300_stencilref_context *sr = r300->stencilref_fallback;
+    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
+    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
+
+    /* Save state. */
+    sr->rs_cull_mode = rs->cull_mode;
+    sr->zb_stencilrefmask = dsa->stencil_ref_mask;
+    sr->ref_value_front = r300->stencil_ref.ref_value[0];
+
+    /* We *cull* pixels, therefore no need to mask out the bits. */
+    rs->cull_mode |= R300_CULL_BACK;
+
+    r300->rs_state.dirty = TRUE;
+}
+
+/* Set drawing for back faces. */
+static void r300_stencilref_switch_side(struct r300_context *r300)
+{
+    struct r300_stencilref_context *sr = r300->stencilref_fallback;
+    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
+    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
+
+    rs->cull_mode = sr->rs_cull_mode | R300_CULL_FRONT;
+    dsa->stencil_ref_mask = dsa->stencil_ref_bf;
+    r300->stencil_ref.ref_value[0] = r300->stencil_ref.ref_value[1];
+
+    r300->rs_state.dirty = TRUE;
+    r300->dsa_state.dirty = TRUE;
+}
+
+/* Restore the original state. */
+static void r300_stencilref_end(struct r300_context *r300)
+{
+    struct r300_stencilref_context *sr = r300->stencilref_fallback;
+    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
+    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
+
+    /* Restore state. */
+    rs->cull_mode = sr->rs_cull_mode;
+    dsa->stencil_ref_mask = sr->zb_stencilrefmask;
+    r300->stencil_ref.ref_value[0] = sr->ref_value_front;
+
+    r300->rs_state.dirty = TRUE;
+    r300->dsa_state.dirty = TRUE;
+}
+
+static void r300_stencilref_draw_arrays(struct pipe_context *pipe, unsigned mode,
+                                        unsigned start, unsigned count)
+{
+    struct r300_context *r300 = r300_context(pipe);
+    struct r300_stencilref_context *sr = r300->stencilref_fallback;
+
+    if (!r300_stencilref_needed(r300)) {
+        sr->draw_arrays(pipe, mode, start, count);
+    } else {
+        r300_stencilref_begin(r300);
+        sr->draw_arrays(pipe, mode, start, count);
+        r300_stencilref_switch_side(r300);
+        sr->draw_arrays(pipe, mode, start, count);
+        r300_stencilref_end(r300);
+    }
+}
+
+static void r300_stencilref_draw_range_elements(
+    struct pipe_context *pipe, struct pipe_resource *indexBuffer,
+    unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex,
+    unsigned mode, unsigned start, unsigned count)
+{
+    struct r300_context *r300 = r300_context(pipe);
+    struct r300_stencilref_context *sr = r300->stencilref_fallback;
+
+    if (!r300_stencilref_needed(r300)) {
+        sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
+                                minIndex, maxIndex, mode, start, count);
+    } else {
+        r300_stencilref_begin(r300);
+        sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
+                                minIndex, maxIndex, mode, start, count);
+        r300_stencilref_switch_side(r300);
+        sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias,
+                                minIndex, maxIndex, mode, start, count);
+        r300_stencilref_end(r300);
+    }
+}
+
+static void r300_plug_in_stencil_ref_fallback(struct r300_context *r300)
+{
+    r300->stencilref_fallback = CALLOC_STRUCT(r300_stencilref_context);
+
+    /* Save original draw functions. */
+    r300->stencilref_fallback->draw_arrays = r300->context.draw_arrays;
+    r300->stencilref_fallback->draw_range_elements = r300->context.draw_range_elements;
+
+    /* Override the draw functions. */
+    r300->context.draw_arrays = r300_stencilref_draw_arrays;
+    r300->context.draw_range_elements = r300_stencilref_draw_range_elements;
+}
+
 void r300_init_render_functions(struct r300_context *r300)
 {
+    /* Set generic functions. */
+    r300->context.draw_elements = r300_draw_elements;
+
+    /* Set draw functions based on presence of HW TCL. */
     if (r300->screen->caps.has_tcl) {
         r300->context.draw_arrays = r300_draw_arrays;
-        r300->context.draw_elements = r300_draw_elements;
         r300->context.draw_range_elements = r300_draw_range_elements;
-
-        if (r300->screen->caps.is_r500) {
-            r300->emit_draw_arrays_immediate = r500_emit_draw_arrays_immediate;
-            r300->emit_draw_arrays = r500_emit_draw_arrays;
-            r300->emit_draw_elements = r500_emit_draw_elements;
-        } else {
-            r300->emit_draw_arrays_immediate = r300_emit_draw_arrays_immediate;
-            r300->emit_draw_arrays = r300_emit_draw_arrays;
-            r300->emit_draw_elements = r300_emit_draw_elements;
-        }
     } else {
         r300->context.draw_arrays = r300_swtcl_draw_arrays;
-        r300->context.draw_elements = r300_draw_elements;
         r300->context.draw_range_elements = r300_swtcl_draw_range_elements;
     }
+
+    /* Plug in two-sided stencil reference value fallback if needed. */
+    if (!r300->screen->caps.is_r500)
+        r300_plug_in_stencil_ref_fallback(r300);
 }
index 46f1653b5bd75dea2cec10fde2711b79ffcf9559..80346e0c79152040622efdc0f594d97fa372adc2 100644 (file)
@@ -474,7 +474,7 @@ static void*
             if (caps->is_r500) {
                 dsa->z_buffer_control |= R500_STENCIL_REFMASK_FRONT_BACK;
             } else {
-                dsa->stencil_ref_bf_fallback =
+                dsa->two_sided_stencil_ref =
                   (state->stencil[0].valuemask != state->stencil[1].valuemask ||
                    state->stencil[0].writemask != state->stencil[1].writemask);
             }
@@ -497,20 +497,6 @@ static void*
     return (void*)dsa;
 }
 
-static void r300_update_stencil_ref_fallback_status(struct r300_context *r300)
-{
-    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
-
-    if (r300->screen->caps.is_r500) {
-        return;
-    }
-
-    r300->stencil_ref_bf_fallback =
-        dsa->stencil_ref_bf_fallback ||
-        (dsa->two_sided &&
-         r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]);
-}
-
 /* Bind DSA state. */
 static void r300_bind_dsa_state(struct pipe_context* pipe,
                                 void* state)
@@ -522,8 +508,6 @@ static void r300_bind_dsa_state(struct pipe_context* pipe,
     }
 
     UPDATE_STATE(state, r300->dsa_state);
-
-    r300_update_stencil_ref_fallback_status(r300);
 }
 
 /* Free DSA state. */
@@ -540,8 +524,6 @@ static void r300_set_stencil_ref(struct pipe_context* pipe,
 
     r300->stencil_ref = *sr;
     r300->dsa_state.dirty = TRUE;
-
-    r300_update_stencil_ref_fallback_status(r300);
 }
 
 /* This switcheroo is needed just because of goddamned MACRO_SWITCH. */