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   assert(svga_have_vgpu10(svga));
83
84   ds->id = util_bitmask_add(svga->ds_object_id_bm);
85
86   /* spot check that these comparision tokens are the same */
87   STATIC_ASSERT(SVGA3D_COMPARISON_NEVER == SVGA3D_CMP_NEVER);
88   STATIC_ASSERT(SVGA3D_COMPARISON_LESS == SVGA3D_CMP_LESS);
89   STATIC_ASSERT(SVGA3D_COMPARISON_NOT_EQUAL == SVGA3D_CMP_NOTEQUAL);
90
91   /* Note: we use the ds->stencil[0].enabled value for both the front
92    * and back-face enables.  If single-side stencil is used, we'll have
93    * set the back state the same as the front state.
94    */
95   SVGA_RETRY(svga, SVGA3D_vgpu10_DefineDepthStencilState
96              (svga->swc,
97               ds->id,
98               /* depth/Z */
99               ds->zenable,
100               ds->zwriteenable,
101               ds->zfunc,
102               /* Stencil */
103               ds->stencil[0].enabled, /*f|b*/
104               ds->stencil[0].enabled, /*f*/
105               ds->stencil[0].enabled, /*b*/
106               ds->stencil_mask,
107               ds->stencil_writemask,
108               /* front stencil */
109               ds->stencil[0].fail,
110               ds->stencil[0].zfail,
111               ds->stencil[0].pass,
112               ds->stencil[0].func,
113               /* back stencil */
114               ds->stencil[1].fail,
115               ds->stencil[1].zfail,
116               ds->stencil[1].pass,
117               ds->stencil[1].func));
118}
119
120
121static void *
122svga_create_depth_stencil_state(struct pipe_context *pipe,
123				const struct pipe_depth_stencil_alpha_state *templ)
124{
125   struct svga_context *svga = svga_context(pipe);
126   struct svga_depth_stencil_state *ds = CALLOC_STRUCT(svga_depth_stencil_state);
127
128   if (!ds)
129      return NULL;
130
131   /* Don't try to figure out CW/CCW correspondence with
132    * stencil[0]/[1] at this point.  Presumably this can change as
133    * back/front face are modified.
134    */
135   ds->stencil[0].enabled = templ->stencil[0].enabled;
136   if (ds->stencil[0].enabled) {
137      ds->stencil[0].func  = svga_translate_compare_func(templ->stencil[0].func);
138      ds->stencil[0].fail  = svga_translate_stencil_op(templ->stencil[0].fail_op);
139      ds->stencil[0].zfail = svga_translate_stencil_op(templ->stencil[0].zfail_op);
140      ds->stencil[0].pass  = svga_translate_stencil_op(templ->stencil[0].zpass_op);
141
142      /* SVGA3D has one ref/mask/writemask triple shared between front &
143       * back face stencil.  We really need two:
144       */
145      ds->stencil_mask      = templ->stencil[0].valuemask & 0xff;
146      ds->stencil_writemask = templ->stencil[0].writemask & 0xff;
147   }
148   else {
149      ds->stencil[0].func = SVGA3D_CMP_ALWAYS;
150      ds->stencil[0].fail = SVGA3D_STENCILOP_KEEP;
151      ds->stencil[0].zfail = SVGA3D_STENCILOP_KEEP;
152      ds->stencil[0].pass = SVGA3D_STENCILOP_KEEP;
153   }
154
155   ds->stencil[1].enabled = templ->stencil[1].enabled;
156   if (templ->stencil[1].enabled) {
157      assert(templ->stencil[0].enabled);
158      /* two-sided stencil */
159      ds->stencil[1].func   = svga_translate_compare_func(templ->stencil[1].func);
160      ds->stencil[1].fail   = svga_translate_stencil_op(templ->stencil[1].fail_op);
161      ds->stencil[1].zfail  = svga_translate_stencil_op(templ->stencil[1].zfail_op);
162      ds->stencil[1].pass   = svga_translate_stencil_op(templ->stencil[1].zpass_op);
163
164      ds->stencil_mask      = templ->stencil[1].valuemask & 0xff;
165      ds->stencil_writemask = templ->stencil[1].writemask & 0xff;
166
167      if (templ->stencil[1].valuemask != templ->stencil[0].valuemask) {
168         util_debug_message(&svga->debug.callback, CONFORMANCE,
169                            "two-sided stencil mask not supported "
170                            "(front=0x%x, back=0x%x)",
171                            templ->stencil[0].valuemask,
172                            templ->stencil[1].valuemask);
173      }
174      if (templ->stencil[1].writemask != templ->stencil[0].writemask) {
175         util_debug_message(&svga->debug.callback, CONFORMANCE,
176                            "two-sided stencil writemask not supported "
177                            "(front=0x%x, back=0x%x)",
178                            templ->stencil[0].writemask,
179                            templ->stencil[1].writemask);
180      }
181   }
182   else {
183      /* back face state is same as front-face state */
184      ds->stencil[1].func = ds->stencil[0].func;
185      ds->stencil[1].fail = ds->stencil[0].fail;
186      ds->stencil[1].zfail = ds->stencil[0].zfail;
187      ds->stencil[1].pass = ds->stencil[0].pass;
188   }
189
190
191   ds->zenable = templ->depth_enabled;
192   if (ds->zenable) {
193      ds->zfunc = svga_translate_compare_func(templ->depth_func);
194      ds->zwriteenable = templ->depth_writemask;
195   }
196   else {
197      ds->zfunc = SVGA3D_CMP_ALWAYS;
198   }
199
200   ds->alphatestenable = templ->alpha_enabled;
201   if (ds->alphatestenable) {
202      ds->alphafunc = svga_translate_compare_func(templ->alpha_func);
203      ds->alpharef = templ->alpha_ref_value;
204   }
205   else {
206      ds->alphafunc = SVGA3D_CMP_ALWAYS;
207   }
208
209   if (svga_have_vgpu10(svga)) {
210      define_depth_stencil_state_object(svga, ds);
211   }
212
213   svga->hud.num_depthstencil_objects++;
214
215   SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
216                        SVGA_STATS_COUNT_DEPTHSTENCILSTATE);
217
218   return ds;
219}
220
221
222static void
223svga_bind_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
224{
225   struct svga_context *svga = svga_context(pipe);
226
227   if (svga_have_vgpu10(svga)) {
228      /* flush any previously queued drawing before changing state */
229      svga_hwtnl_flush_retry(svga);
230   }
231
232   svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil;
233   svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA;
234}
235
236
237static void
238svga_delete_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil)
239{
240   struct svga_context *svga = svga_context(pipe);
241   struct svga_depth_stencil_state *ds =
242      (struct svga_depth_stencil_state *) depth_stencil;
243
244   if (svga_have_vgpu10(svga)) {
245      svga_hwtnl_flush_retry(svga);
246
247      assert(ds->id != SVGA3D_INVALID_ID);
248
249      SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc,
250                                                              ds->id));
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
293static void
294svga_set_min_samples(struct pipe_context *pipe, unsigned min_samples)
295{
296   /* This specifies the minimum number of times the fragment shader
297    * must run when doing per-sample shading for a MSAA render target.
298    * For our SVGA3D device, the FS is automatically run in per-sample
299    * mode if it uses the sample ID or sample position registers.
300    */
301}
302
303
304void
305svga_init_depth_stencil_functions(struct svga_context *svga)
306{
307   svga->pipe.create_depth_stencil_alpha_state = svga_create_depth_stencil_state;
308   svga->pipe.bind_depth_stencil_alpha_state = svga_bind_depth_stencil_state;
309   svga->pipe.delete_depth_stencil_alpha_state = svga_delete_depth_stencil_state;
310
311   svga->pipe.set_stencil_ref = svga_set_stencil_ref;
312   svga->pipe.set_sample_mask = svga_set_sample_mask;
313   svga->pipe.set_min_samples = svga_set_min_samples;
314}
315