1/*
2 * Copyright 2010 Marek Olšák <maraeo@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23/**
24 * The two-sided stencil reference value fallback for r3xx-r4xx chips.
25 * These chips support two-sided stencil functions but they do not support
26 * a two-sided reference value.
27 *
28 * The functions below split every draw call which uses the two-sided
29 * reference value into two draw calls -- the first one renders front faces
30 * and the second renders back faces with the other reference value.
31 */
32
33#include "r300_context.h"
34#include "r300_reg.h"
35
36struct r300_stencilref_context {
37    void (*draw_vbo)(struct pipe_context *pipe,
38                     const struct pipe_draw_info *info,
39                     unsigned drawid_offset,
40                     const struct pipe_draw_indirect_info *indirect,
41                     const struct pipe_draw_start_count_bias *draws,
42                     unsigned num_draws);
43
44    uint32_t rs_cull_mode;
45    uint32_t zb_stencilrefmask;
46    ubyte ref_value_front;
47};
48
49static boolean r300_stencilref_needed(struct r300_context *r300)
50{
51    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
52
53    return dsa->two_sided_stencil_ref ||
54           (dsa->two_sided &&
55            r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]);
56}
57
58/* Set drawing for front faces. */
59static void r300_stencilref_begin(struct r300_context *r300)
60{
61    struct r300_stencilref_context *sr = r300->stencilref_fallback;
62    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
63    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
64
65    /* Save state. */
66    sr->rs_cull_mode = rs->cb_main[rs->cull_mode_index];
67    sr->zb_stencilrefmask = dsa->stencil_ref_mask;
68    sr->ref_value_front = r300->stencil_ref.ref_value[0];
69
70    /* We *cull* pixels, therefore no need to mask out the bits. */
71    rs->cb_main[rs->cull_mode_index] |= R300_CULL_BACK;
72
73    r300_mark_atom_dirty(r300, &r300->rs_state);
74}
75
76/* Set drawing for back faces. */
77static void r300_stencilref_switch_side(struct r300_context *r300)
78{
79    struct r300_stencilref_context *sr = r300->stencilref_fallback;
80    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
81    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
82
83    rs->cb_main[rs->cull_mode_index] = sr->rs_cull_mode | R300_CULL_FRONT;
84    dsa->stencil_ref_mask = dsa->stencil_ref_bf;
85    r300->stencil_ref.ref_value[0] = r300->stencil_ref.ref_value[1];
86
87    r300_mark_atom_dirty(r300, &r300->rs_state);
88    r300_mark_atom_dirty(r300, &r300->dsa_state);
89}
90
91/* Restore the original state. */
92static void r300_stencilref_end(struct r300_context *r300)
93{
94    struct r300_stencilref_context *sr = r300->stencilref_fallback;
95    struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state;
96    struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state;
97
98    /* Restore state. */
99    rs->cb_main[rs->cull_mode_index] = sr->rs_cull_mode;
100    dsa->stencil_ref_mask = sr->zb_stencilrefmask;
101    r300->stencil_ref.ref_value[0] = sr->ref_value_front;
102
103    r300_mark_atom_dirty(r300, &r300->rs_state);
104    r300_mark_atom_dirty(r300, &r300->dsa_state);
105}
106
107static void r300_stencilref_draw_vbo(struct pipe_context *pipe,
108                                     const struct pipe_draw_info *info,
109                                     unsigned drawid_offset,
110                                     const struct pipe_draw_indirect_info *indirect,
111                                     const struct pipe_draw_start_count_bias *draws,
112                                     unsigned num_draws)
113{
114    struct r300_context *r300 = r300_context(pipe);
115    struct r300_stencilref_context *sr = r300->stencilref_fallback;
116
117    if (!r300_stencilref_needed(r300)) {
118        sr->draw_vbo(pipe, info, drawid_offset, NULL, draws, num_draws);
119    } else {
120        r300_stencilref_begin(r300);
121        sr->draw_vbo(pipe, info, drawid_offset, NULL, draws, num_draws);
122        r300_stencilref_switch_side(r300);
123        sr->draw_vbo(pipe, info, drawid_offset, NULL, draws, num_draws);
124        r300_stencilref_end(r300);
125    }
126}
127
128void r300_plug_in_stencil_ref_fallback(struct r300_context *r300)
129{
130    r300->stencilref_fallback = CALLOC_STRUCT(r300_stencilref_context);
131
132    /* Save original draw function. */
133    r300->stencilref_fallback->draw_vbo = r300->context.draw_vbo;
134
135    /* Override the draw function. */
136    r300->context.draw_vbo = r300_stencilref_draw_vbo;
137}
138