gallium/svga: Upload only parts of user-buffers that we actually use
[mesa.git] / src / gallium / drivers / svga / svga_pipe_draw.c
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 "svga_cmd.h"
27
28 #include "util/u_inlines.h"
29 #include "util/u_prim.h"
30 #include "util/u_time.h"
31 #include "indices/u_indices.h"
32
33 #include "svga_hw_reg.h"
34 #include "svga_context.h"
35 #include "svga_screen.h"
36 #include "svga_draw.h"
37 #include "svga_state.h"
38 #include "svga_swtnl.h"
39 #include "svga_debug.h"
40 #include "svga_resource_buffer.h"
41 #include "util/u_upload_mgr.h"
42
43 /**
44 * svga_upload_user_buffers - upload parts of user buffers
45 *
46 * This function streams a part of a user buffer to hw and sets
47 * svga_buffer::source_offset to the first byte uploaded. After upload
48 * also svga_buffer::uploaded::buffer is set to !NULL
49 */
50
51 static int
52 svga_upload_user_buffers(struct svga_context *svga,
53 unsigned start,
54 unsigned count,
55 unsigned instance_count)
56 {
57 const struct pipe_vertex_element *ve = svga->curr.velems->velem;
58 unsigned i;
59 int ret;
60
61 for (i=0; i < svga->curr.velems->count; i++) {
62 struct pipe_vertex_buffer *vb =
63 &svga->curr.vb[ve[i].vertex_buffer_index];
64
65 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
66 struct svga_buffer *buffer = svga_buffer(vb->buffer);
67 unsigned first, size;
68 boolean flushed;
69 unsigned instance_div = ve[i].instance_divisor;
70
71 svga->dirty |= SVGA_NEW_VBUFFER;
72
73 if (instance_div) {
74 first = 0;
75 size = vb->stride *
76 (instance_count + instance_div - 1) / instance_div;
77 } else if (vb->stride) {
78 first = vb->stride * start;
79 size = vb->stride * count;
80 } else {
81 /* Only a single vertex!
82 * Upload with the largest vertex size the hw supports,
83 * if possible.
84 */
85 first = 0;
86 size = MIN2(16, vb->buffer->width0);
87 }
88
89 ret = u_upload_buffer( svga->upload_vb,
90 0, first, size,
91 &buffer->b.b,
92 &buffer->uploaded.offset,
93 &buffer->uploaded.buffer,
94 &flushed);
95
96 if (ret)
97 return ret;
98
99 if (0)
100 debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d"
101 " sz %d\n",
102 __FUNCTION__,
103 i,
104 buffer,
105 buffer->uploaded.buffer,
106 buffer->uploaded.offset,
107 first,
108 size);
109
110 vb->buffer_offset = buffer->uploaded.offset;
111 buffer->source_offset = first;
112 }
113 }
114
115 return PIPE_OK;
116 }
117
118 /**
119 * svga_release_user_upl_buffers - release uploaded parts of user buffers
120 *
121 * This function releases the hw copy of the uploaded fraction of the
122 * user-buffer. It's important to do this as soon as all draw calls
123 * affecting the uploaded fraction are issued, as this allows for
124 * efficient reuse of the hardware surface backing the uploaded fraction.
125 *
126 * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer
127 * is set to 0.
128 */
129
130 static void
131 svga_release_user_upl_buffers(struct svga_context *svga)
132 {
133 unsigned i;
134 unsigned nr;
135
136 nr = svga->curr.num_vertex_buffers;
137
138 for (i = 0; i < nr; ++i) {
139 struct pipe_vertex_buffer *vb = &svga->curr.vb[i];
140
141 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
142 struct svga_buffer *buffer = svga_buffer(vb->buffer);
143
144 buffer->source_offset = 0;
145 if (buffer->uploaded.buffer)
146 pipe_resource_reference(&buffer->uploaded.buffer, NULL);
147 }
148 }
149 }
150
151
152
153 static enum pipe_error
154 retry_draw_range_elements( struct svga_context *svga,
155 struct pipe_resource *index_buffer,
156 unsigned index_size,
157 int index_bias,
158 unsigned min_index,
159 unsigned max_index,
160 unsigned prim,
161 unsigned start,
162 unsigned count,
163 unsigned instance_count,
164 boolean do_retry )
165 {
166 enum pipe_error ret = 0;
167
168 svga_hwtnl_set_unfilled( svga->hwtnl,
169 svga->curr.rast->hw_unfilled );
170
171 svga_hwtnl_set_flatshade( svga->hwtnl,
172 svga->curr.rast->templ.flatshade,
173 svga->curr.rast->templ.flatshade_first );
174
175 ret = svga_upload_user_buffers( svga, min_index + index_bias,
176 max_index - min_index + 1, instance_count );
177 if (ret != PIPE_OK)
178 goto retry;
179
180 ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
181 if (ret)
182 goto retry;
183
184 ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
185 index_buffer, index_size, index_bias,
186 min_index, max_index,
187 prim, start, count );
188 if (ret)
189 goto retry;
190
191 return PIPE_OK;
192
193 retry:
194 svga_context_flush( svga, NULL );
195
196 if (do_retry)
197 {
198 return retry_draw_range_elements( svga,
199 index_buffer, index_size, index_bias,
200 min_index, max_index,
201 prim, start, count,
202 instance_count, FALSE );
203 }
204
205 return ret;
206 }
207
208
209 static enum pipe_error
210 retry_draw_arrays( struct svga_context *svga,
211 unsigned prim,
212 unsigned start,
213 unsigned count,
214 unsigned instance_count,
215 boolean do_retry )
216 {
217 enum pipe_error ret;
218
219 svga_hwtnl_set_unfilled( svga->hwtnl,
220 svga->curr.rast->hw_unfilled );
221
222 svga_hwtnl_set_flatshade( svga->hwtnl,
223 svga->curr.rast->templ.flatshade,
224 svga->curr.rast->templ.flatshade_first );
225
226 ret = svga_upload_user_buffers( svga, start, count, instance_count );
227
228 if (ret != PIPE_OK)
229 goto retry;
230
231 ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
232 if (ret)
233 goto retry;
234
235 ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
236 start, count );
237 if (ret)
238 goto retry;
239
240 return 0;
241
242 retry:
243 if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
244 {
245 svga_context_flush( svga, NULL );
246
247 return retry_draw_arrays( svga,
248 prim,
249 start,
250 count,
251 instance_count,
252 FALSE );
253 }
254
255 return ret;
256 }
257
258
259 static void
260 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
261 {
262 struct svga_context *svga = svga_context( pipe );
263 unsigned reduced_prim = u_reduced_prim( info->mode );
264 unsigned count = info->count;
265 enum pipe_error ret = 0;
266 boolean needed_swtnl;
267
268 if (!u_trim_pipe_prim( info->mode, &count ))
269 return;
270
271 /*
272 * Mark currently bound target surfaces as dirty
273 * doesn't really matter if it is done before drawing.
274 *
275 * TODO If we ever normaly return something other then
276 * true we should not mark it as dirty then.
277 */
278 svga_mark_surfaces_dirty(svga_context(pipe));
279
280 if (svga->curr.reduced_prim != reduced_prim) {
281 svga->curr.reduced_prim = reduced_prim;
282 svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
283 }
284
285 needed_swtnl = svga->state.sw.need_swtnl;
286
287 svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
288
289 #ifdef DEBUG
290 if (svga->curr.vs->base.id == svga->debug.disable_shader ||
291 svga->curr.fs->base.id == svga->debug.disable_shader)
292 return;
293 #endif
294
295 if (svga->state.sw.need_swtnl) {
296 if (!needed_swtnl) {
297 /*
298 * We're switching from HW to SW TNL. SW TNL will require mapping all
299 * currently bound vertex buffers, some of which may already be
300 * referenced in the current command buffer as result of previous HW
301 * TNL. So flush now, to prevent the context to flush while a referred
302 * vertex buffer is mapped.
303 */
304
305 svga_context_flush(svga, NULL);
306 }
307
308 /* Avoid leaking the previous hwtnl bias to swtnl */
309 svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
310 ret = svga_swtnl_draw_vbo( svga, info );
311 }
312 else {
313 if (info->indexed && svga->curr.ib.buffer) {
314 unsigned offset;
315
316 assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
317 offset = svga->curr.ib.offset / svga->curr.ib.index_size;
318
319 ret = retry_draw_range_elements( svga,
320 svga->curr.ib.buffer,
321 svga->curr.ib.index_size,
322 info->index_bias,
323 info->min_index,
324 info->max_index,
325 info->mode,
326 info->start + offset,
327 info->count,
328 info->instance_count,
329 TRUE );
330 }
331 else {
332 ret = retry_draw_arrays( svga,
333 info->mode,
334 info->start,
335 info->count,
336 info->instance_count,
337 TRUE );
338 }
339 }
340
341 svga_release_user_upl_buffers( svga );
342
343 if (SVGA_DEBUG & DEBUG_FLUSH) {
344 svga_hwtnl_flush_retry( svga );
345 svga_context_flush(svga, NULL);
346 }
347 }
348
349
350 void svga_init_draw_functions( struct svga_context *svga )
351 {
352 svga->pipe.draw_vbo = svga_draw_vbo;
353 }