• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 #include "util/u_format.h"
28 #include "util/u_helpers.h"
29 #include "util/u_inlines.h"
30 #include "util/u_prim.h"
31 #include "util/u_prim_restart.h"
32 #include "util/u_upload_mgr.h"
33 #include "indices/u_indices.h"
34 
35 #include "svga_hw_reg.h"
36 #include "svga_cmd.h"
37 #include "svga_context.h"
38 #include "svga_screen.h"
39 #include "svga_draw.h"
40 #include "svga_shader.h"
41 #include "svga_state.h"
42 #include "svga_surface.h"
43 #include "svga_swtnl.h"
44 #include "svga_debug.h"
45 #include "svga_resource_buffer.h"
46 
47 /* Returns TRUE if we are currently using flat shading.
48  */
49 static boolean
is_using_flat_shading(const struct svga_context * svga)50 is_using_flat_shading(const struct svga_context *svga)
51 {
52    return
53       svga->state.hw_draw.fs ? svga->state.hw_draw.fs->uses_flat_interp : FALSE;
54 }
55 
56 
57 static enum pipe_error
retry_draw_range_elements(struct svga_context * svga,struct pipe_resource * index_buffer,unsigned index_size,int index_bias,unsigned min_index,unsigned max_index,enum pipe_prim_type prim,unsigned start,unsigned count,unsigned start_instance,unsigned instance_count,boolean do_retry)58 retry_draw_range_elements( struct svga_context *svga,
59                            struct pipe_resource *index_buffer,
60                            unsigned index_size,
61                            int index_bias,
62                            unsigned min_index,
63                            unsigned max_index,
64                            enum pipe_prim_type prim,
65                            unsigned start,
66                            unsigned count,
67                            unsigned start_instance,
68                            unsigned instance_count,
69                            boolean do_retry )
70 {
71    enum pipe_error ret = PIPE_OK;
72 
73    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS);
74 
75    svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
76 
77    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
78    if (ret != PIPE_OK)
79       goto retry;
80 
81    /** determine if flatshade is to be used after svga_update_state()
82     *  in case the fragment shader is changed.
83     */
84    svga_hwtnl_set_flatshade(svga->hwtnl,
85                             svga->curr.rast->templ.flatshade ||
86                             is_using_flat_shading(svga),
87                             svga->curr.rast->templ.flatshade_first);
88 
89    ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
90                                          index_buffer, index_size, index_bias,
91                                          min_index, max_index,
92                                          prim, start, count,
93                                          start_instance, instance_count);
94    if (ret != PIPE_OK)
95       goto retry;
96 
97    goto done;
98 
99 retry:
100    svga_context_flush( svga, NULL );
101 
102    if (do_retry)
103    {
104       ret = retry_draw_range_elements(svga,
105                                       index_buffer, index_size, index_bias,
106                                       min_index, max_index,
107                                       prim, start, count,
108                                       start_instance, instance_count, FALSE);
109    }
110 
111 done:
112    SVGA_STATS_TIME_POP(svga_sws(svga));
113    return ret;
114 }
115 
116 
117 static enum pipe_error
retry_draw_arrays(struct svga_context * svga,enum pipe_prim_type prim,unsigned start,unsigned count,unsigned start_instance,unsigned instance_count,boolean do_retry)118 retry_draw_arrays( struct svga_context *svga,
119                    enum pipe_prim_type prim, unsigned start, unsigned count,
120                    unsigned start_instance, unsigned instance_count,
121                    boolean do_retry )
122 {
123    enum pipe_error ret;
124 
125    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS);
126 
127    svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
128 
129    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
130    if (ret != PIPE_OK)
131       goto retry;
132 
133    /** determine if flatshade is to be used after svga_update_state()
134     *  in case the fragment shader is changed.
135     */
136    svga_hwtnl_set_flatshade(svga->hwtnl,
137                             svga->curr.rast->templ.flatshade ||
138                             is_using_flat_shading(svga),
139                             svga->curr.rast->templ.flatshade_first);
140 
141    ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count,
142                                 start_instance, instance_count);
143    if (ret != PIPE_OK)
144       goto retry;
145 
146    goto done;
147 
148 retry:
149    if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
150    {
151       svga_context_flush( svga, NULL );
152 
153       ret = retry_draw_arrays(svga, prim, start, count,
154                               start_instance, instance_count,
155                               FALSE);
156    }
157 
158 done:
159    SVGA_STATS_TIME_POP(svga_sws(svga));
160    return ret;
161 }
162 
163 
164 /**
165  * Determine if we need to implement primitive restart with a fallback
166  * path which breaks the original primitive into sub-primitive at the
167  * restart indexes.
168  */
169 static boolean
need_fallback_prim_restart(const struct svga_context * svga,const struct pipe_draw_info * info)170 need_fallback_prim_restart(const struct svga_context *svga,
171                            const struct pipe_draw_info *info)
172 {
173    if (info->primitive_restart && info->index_size) {
174       if (!svga_have_vgpu10(svga))
175          return TRUE;
176       else if (!svga->state.sw.need_swtnl) {
177          if (info->index_size == 1)
178             return TRUE; /* no device support for 1-byte indexes */
179          else if (info->index_size == 2)
180             return info->restart_index != 0xffff;
181          else
182             return info->restart_index != 0xffffffff;
183       }
184    }
185 
186    return FALSE;
187 }
188 
189 
190 static void
svga_draw_vbo(struct pipe_context * pipe,const struct pipe_draw_info * info)191 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
192 {
193    struct svga_context *svga = svga_context( pipe );
194    enum pipe_prim_type reduced_prim = u_reduced_prim( info->mode );
195    unsigned count = info->count;
196    enum pipe_error ret = 0;
197    boolean needed_swtnl;
198    struct pipe_resource *indexbuf =
199       info->has_user_indices ? NULL : info->index.resource;
200 
201    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWVBO);
202 
203    svga->hud.num_draw_calls++;  /* for SVGA_QUERY_NUM_DRAW_CALLS */
204 
205    if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES &&
206        svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK)
207       goto done;
208 
209    /* Upload a user index buffer. */
210    unsigned index_offset = 0;
211    if (info->index_size && info->has_user_indices &&
212        !util_upload_index_buffer(pipe, info, &indexbuf, &index_offset)) {
213       goto done;
214    }
215 
216    /*
217     * Mark currently bound target surfaces as dirty
218     * doesn't really matter if it is done before drawing.
219     *
220     * TODO If we ever normaly return something other then
221     * true we should not mark it as dirty then.
222     */
223    svga_mark_surfaces_dirty(svga_context(pipe));
224 
225    if (svga->curr.reduced_prim != reduced_prim) {
226       svga->curr.reduced_prim = reduced_prim;
227       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
228    }
229 
230    if (need_fallback_prim_restart(svga, info)) {
231       enum pipe_error r;
232       r = util_draw_vbo_without_prim_restart(pipe, info);
233       assert(r == PIPE_OK);
234       (void) r;
235       goto done;
236    }
237 
238    if (!u_trim_pipe_prim( info->mode, &count ))
239       goto done;
240 
241    needed_swtnl = svga->state.sw.need_swtnl;
242 
243    svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
244 
245    if (svga->state.sw.need_swtnl) {
246       svga->hud.num_fallbacks++;  /* for SVGA_QUERY_NUM_FALLBACKS */
247       if (!needed_swtnl) {
248          /*
249           * We're switching from HW to SW TNL.  SW TNL will require mapping all
250           * currently bound vertex buffers, some of which may already be
251           * referenced in the current command buffer as result of previous HW
252           * TNL. So flush now, to prevent the context to flush while a referred
253           * vertex buffer is mapped.
254           */
255 
256          svga_context_flush(svga, NULL);
257       }
258 
259       /* Avoid leaking the previous hwtnl bias to swtnl */
260       svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
261       ret = svga_swtnl_draw_vbo(svga, info, indexbuf, index_offset);
262    }
263    else {
264       if (info->index_size && indexbuf) {
265          unsigned offset;
266 
267          assert(index_offset % info->index_size == 0);
268          offset = index_offset / info->index_size;
269 
270          ret = retry_draw_range_elements( svga,
271                                           indexbuf,
272                                           info->index_size,
273                                           info->index_bias,
274                                           info->min_index,
275                                           info->max_index,
276                                           info->mode,
277                                           info->start + offset,
278                                           count,
279                                           info->start_instance,
280                                           info->instance_count,
281                                           TRUE );
282       }
283       else {
284          ret = retry_draw_arrays(svga, info->mode, info->start, count,
285                                  info->start_instance, info->instance_count,
286                                  TRUE);
287       }
288    }
289 
290    /* XXX: Silence warnings, do something sensible here? */
291    (void)ret;
292 
293    if (SVGA_DEBUG & DEBUG_FLUSH) {
294       svga_hwtnl_flush_retry( svga );
295       svga_context_flush(svga, NULL);
296    }
297 
298 done:
299    if (info->index_size && info->index.resource != indexbuf)
300       pipe_resource_reference(&indexbuf, NULL);
301    SVGA_STATS_TIME_POP(svga_sws(svga));
302 }
303 
304 
svga_init_draw_functions(struct svga_context * svga)305 void svga_init_draw_functions( struct svga_context *svga )
306 {
307    svga->pipe.draw_vbo = svga_draw_vbo;
308 }
309