1/**********************************************************
2 * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26#include "pipe/p_defines.h"
27#include "util/u_bitmask.h"
28#include "util/u_inlines.h"
29#include "util/u_math.h"
30#include "util/u_memory.h"
31
32#include "svga_context.h"
33#include "svga_hw_reg.h"
34#include "svga_cmd.h"
35
36
37static inline unsigned
38svga_translate_compare_func(unsigned func)
39{
40   switch (func) {
41   case PIPE_FUNC_NEVER:     return SVGA3D_CMP_NEVER;
42   case PIPE_FUNC_LESS:      return SVGA3D_CMP_LESS;
43   case PIPE_FUNC_LEQUAL:    return SVGA3D_CMP_LESSEQUAL;
44   case PIPE_FUNC_GREATER:   return SVGA3D_CMP_GREATER;
45   case PIPE_FUNC_GEQUAL:    return SVGA3D_CMP_GREATEREQUAL;
46   case PIPE_FUNC_NOTEQUAL:  return SVGA3D_CMP_NOTEQUAL;
47   case PIPE_FUNC_EQUAL:     return SVGA3D_CMP_EQUAL;
48   case PIPE_FUNC_ALWAYS:    return SVGA3D_CMP_ALWAYS;
49   default:
50      assert(0);
51      return SVGA3D_CMP_ALWAYS;
52   }
53}
54
55static inline unsigned
56svga_translate_stencil_op(unsigned op)
57{
58   switch (op) {
59   case PIPE_STENCIL_OP_KEEP:      return SVGA3D_STENCILOP_KEEP;
60   case PIPE_STENCIL_OP_ZERO:      return SVGA3D_STENCILOP_ZERO;
61   case PIPE_STENCIL_OP_REPLACE:   return SVGA3D_STENCILOP_REPLACE;
62   case PIPE_STENCIL_OP_INCR:      return SVGA3D_STENCILOP_INCRSAT;
63   case PIPE_STENCIL_OP_DECR:      return SVGA3D_STENCILOP_DECRSAT;
64   case PIPE_STENCIL_OP_INCR_WRAP: return SVGA3D_STENCILOP_INCR;
65   case PIPE_STENCIL_OP_DECR_WRAP: return SVGA3D_STENCILOP_DECR;
66   case PIPE_STENCIL_OP_INVERT:    return SVGA3D_STENCILOP_INVERT;
67   default:
68      assert(0);
69      return SVGA3D_STENCILOP_KEEP;
70   }
71}
72
73
74/**
75 * Define a vgpu10 depth/stencil state object for the given
76 * svga depth/stencil state.
77 */
78static void
79define_depth_stencil_state_object(struct svga_context *svga,
80                                  struct svga_depth_stencil_state *ds)
81{
82   unsigned try;
83
84   assert(svga_have_vgpu10(svga));
85
86   ds->id = util_bitmask_add(svga->ds_object_id_bm);
87
88   /* spot check that these comparision tokens are the same */
89   STATIC_ASSERT(SVGA3D_COMPARISON_NEVER == SVGA3D_CMP_NEVER);
90   STATIC_ASSERT(SVGA3D_COMPARISON_LESS == SVGA3D_CMP_LESS);
91   STATIC_ASSERT(SVGA3D_COMPARISON_NOT_EQUAL == SVGA3D_CMP_NOTEQUAL);
92
93   /* Loop in case command buffer is full and we need to flush and retry */
94   for (try = 0; try < 2; try++) {
95      enum pipe_error ret;
96
97      /* Note: we use the ds->stencil[0].enabled value for both the front
98       * and back-face enables.  If single-side stencil is used, we'll have
99       * set the back state the same as the front state.
100       */
101      ret = SVGA3D_vgpu10_DefineDepthStencilState(svga->swc,
102                                                  ds->id,
103                                                  /* depth/Z */
104                                                  ds->zenable,
105                                                  ds->zwriteenable,
106                                                  ds->zfunc,
107                                                  /* Stencil */
108                                                  ds->stencil[0].enabled, /*f|b*/
109                                                  ds->stencil[0].enabled, /*f*/
110                                                  ds->stencil[0].enabled, /*b*/
111                                                  ds->stencil_mask,
112                                                  ds->stencil_writemask,
113                                                  /* front stencil */
114                                                  ds->stencil[0].fail,
115                                                  ds->stencil[0].zfail,
116                                                  ds->stencil[0].pass,
117                                                  ds->stencil[0].func,
118                                                  /* back stencil */
119                                                  ds->stencil[1].fail,
120                                                  ds->stencil[1].zfail,
121                                                  ds->stencil[1].pass,
122                                                  ds->stencil[1].func);
123      if (ret == PIPE_OK)
124         return;
125      svga_context_flush(svga, NULL);
126   }
127}
128
129
130static void *
131svga_create_depth_stencil_state(struct pipe_context *pipe,
132				const struct pipe_depth_stencil_alpha_state *templ)
133{
134   struct svga_context *svga = svga_context(pipe);
135   struct svga_depth_stencil_state *ds = CALLOC_STRUCT(svga_depth_stencil_state);
136
137   if (!ds)
138      return NULL;
139
140   /* Don't try to figure out CW/CCW correspondence with
141    * stencil[0]/[1] at this point.  Presumably this can change as
142    * back/front face are modified.
143    */
144   ds->stencil[0].enabled = templ->stencil[0].enabled;
145   if (ds->stencil[0].enabled) {
146      ds->stencil[0].func  = svga_translate_compare_func(templ->stencil[0].func);
147      ds->stencil[0].fail  = svga_translate_stencil_op(templ->stencil[0].fail_op);
148      ds->stencil[0].zfail = svga_translate_stencil_op(templ->stencil[0].zfail_op);
149      ds->stencil[0].pass  = svga_translate_stencil_op(templ->stencil[0].zpass_op);
150
151      /* SVGA3D has one ref/mask/writemask triple shared between front &
152       * back face stencil.  We really need two:
153       */
154      ds->stencil_mask      = templ->stencil[0].valuemask & 0xff;
155      ds->stencil_writemask = templ->stencil[0].writemask & 0xff;
156   }
157   else {
158      ds->stencil[0].func = SVGA3D_CMP_ALWAYS;
159      ds->stencil[0].fail = SVGA3D_STENCILOP_KEEP;
160      ds->stencil[0].zfail = SVGA3D_STENCILOP_KEEP;
161      ds->stencil[0].pass = SVGA3D_STENCILOP_KEEP;
162   }
163
164   ds->stencil[1].enabled = templ->stencil[1].enabled;
165   if (templ->stencil[1].enabled) {
166      assert(templ->stencil[0].enabled);
167      /* two-sided stencil */
168      ds->stencil[1].func   = svga_translate_compare_func(templ->stencil[1].func);
169      ds->stencil[1].fail   = svga_translate_stencil_op(templ->stencil[1].fail_op);
170      ds->stencil[1].zfail  = svga_translate_stencil_op(templ->stencil[1].zfail_op);
171      ds->stencil[1].pass   = svga_translate_stencil_op(templ->stencil[1].zpass_op);
172
173      ds->stencil_mask      = templ->stencil[1].valuemask & 0xff;
174      ds->stencil_writemask = templ->stencil[1].writemask & 0xff;
175   }
176   else {
177      /* back face state is same as front-face state */
178      ds->stencil[1].func = ds->stencil[0].func;
179      ds->stencil[1].fail = ds->stencil[0].fail;
180      ds->stencil[1].zfail = ds->stencil[0].zfail;
181      ds->stencil[1].pass = ds->stencil[0].pass;
182   }
183
184
185   ds->zenable = templ->depth.enabled;
186   if (ds->zenable) {
187      ds->zfunc = svga_translate_compare_func(templ->depth.func);
188      ds->zwriteenable = templ->depth.writemask;
189   }
190   else {
191      ds->zfunc = SVGA3D_CMP_ALWAYS;
192   }
193
194   ds->alphatestenable = templ->alpha.enabled;
195   if (ds->alphatestenable) {
196      ds->alphafunc = svga_translate_compare_func(templ->alpha.func);
197      ds->alpharef = templ->alpha.ref_value;
198   }
199   else {
200      ds->alphafunc = SVGA3D_CMP_ALWAYS;
201   }
202
203   if (svga_have_vgpu10(svga)) {
204      define_depth_stencil_state_object(svga, ds);
205   }
206
207   svga->hud.num_depthstencil_objects++;
208
209   SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
210                        SVGA_STATS_COUNT_DEPTHSTENCILSTATE);
211
212   return ds;
213}
214
215
216static void
217svga_bind_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
218{
219   struct svga_context *svga = svga_context(pipe);
220
221   if (svga_have_vgpu10(svga)) {
222      /* flush any previously queued drawing before changing state */
223      svga_hwtnl_flush_retry(svga);
224   }
225
226   svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil;
227   svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA;
228}
229
230
231static void
232svga_delete_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
233{
234   struct svga_context *svga = svga_context(pipe);
235   struct svga_depth_stencil_state *ds =
236      (struct svga_depth_stencil_state *) depth_stencil;
237
238   if (svga_have_vgpu10(svga)) {
239      enum pipe_error ret;
240
241      svga_hwtnl_flush_retry(svga);
242
243      assert(ds->id != SVGA3D_INVALID_ID);
244
245      ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id);
246      if (ret != PIPE_OK) {
247         svga_context_flush(svga, NULL);
248         ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id);
249         assert(ret == PIPE_OK);
250      }
251
252      if (ds->id == svga->state.hw_draw.depth_stencil_id)
253         svga->state.hw_draw.depth_stencil_id = SVGA3D_INVALID_ID;
254
255      util_bitmask_clear(svga->ds_object_id_bm, ds->id);
256      ds->id = SVGA3D_INVALID_ID;
257   }
258
259   FREE(depth_stencil);
260   svga->hud.num_depthstencil_objects--;
261}
262
263
264static void
265svga_set_stencil_ref(struct pipe_context *pipe,
266                     const struct pipe_stencil_ref *stencil_ref)
267{
268   struct svga_context *svga = svga_context(pipe);
269
270   if (svga_have_vgpu10(svga)) {
271      /* flush any previously queued drawing before changing state */
272      svga_hwtnl_flush_retry(svga);
273   }
274
275   svga->curr.stencil_ref = *stencil_ref;
276
277   svga->dirty |= SVGA_NEW_STENCIL_REF;
278}
279
280
281static void
282svga_set_sample_mask(struct pipe_context *pipe,
283                     unsigned sample_mask)
284{
285   struct svga_context *svga = svga_context(pipe);
286
287   svga->curr.sample_mask = sample_mask;
288
289   svga->dirty |= SVGA_NEW_BLEND; /* See emit_rss_vgpu10() */
290}
291
292
293void
294svga_init_depth_stencil_functions(struct svga_context *svga)
295{
296   svga->pipe.create_depth_stencil_alpha_state = svga_create_depth_stencil_state;
297   svga->pipe.bind_depth_stencil_alpha_state = svga_bind_depth_stencil_state;
298   svga->pipe.delete_depth_stencil_alpha_state = svga_delete_depth_stencil_state;
299
300   svga->pipe.set_stencil_ref = svga_set_stencil_ref;
301   svga->pipe.set_sample_mask = svga_set_sample_mask;
302}
303