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