Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5563 serge 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_time.h"
31
#include "util/u_upload_mgr.h"
32
#include "indices/u_indices.h"
33
 
34
#include "svga_hw_reg.h"
35
#include "svga_cmd.h"
36
#include "svga_context.h"
37
#include "svga_screen.h"
38
#include "svga_draw.h"
39
#include "svga_state.h"
40
#include "svga_swtnl.h"
41
#include "svga_debug.h"
42
#include "svga_resource_buffer.h"
43
 
44
 
45
/**
46
 * Determine the ranges to upload for the user-buffers referenced
47
 * by the next draw command.
48
 *
49
 * TODO: It might be beneficial to support multiple ranges. In that case,
50
 * the struct svga_buffer::uploaded member should be made an array or a
51
 * list, since we need to account for the possibility that different ranges
52
 * may be uploaded to different hardware buffers chosen by the utility
53
 * upload manager.
54
 */
55
static void
56
svga_user_buffer_range(struct svga_context *svga,
57
                       unsigned start,
58
                       unsigned count,
59
                       unsigned instance_count)
60
{
61
   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
62
   unsigned i;
63
 
64
   /*
65
    * Release old uploaded range (if not done already) and
66
    * initialize new ranges.
67
    */
68
 
69
   for (i=0; i < svga->curr.velems->count; i++) {
70
      struct pipe_vertex_buffer *vb =
71
         &svga->curr.vb[ve[i].vertex_buffer_index];
72
 
73
      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
74
         struct svga_buffer *buffer = svga_buffer(vb->buffer);
75
 
76
         pipe_resource_reference(&buffer->uploaded.buffer, NULL);
77
         buffer->uploaded.start = ~0;
78
         buffer->uploaded.end = 0;
79
      }
80
   }
81
 
82
   for (i=0; i < svga->curr.velems->count; i++) {
83
      struct pipe_vertex_buffer *vb =
84
         &svga->curr.vb[ve[i].vertex_buffer_index];
85
 
86
      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
87
         struct svga_buffer *buffer = svga_buffer(vb->buffer);
88
         unsigned first, size;
89
         unsigned instance_div = ve[i].instance_divisor;
90
         unsigned elemSize = util_format_get_blocksize(ve[i].src_format);
91
 
92
         svga->dirty |= SVGA_NEW_VBUFFER;
93
 
94
         if (instance_div) {
95
            first = ve[i].src_offset;
96
            count = (instance_count + instance_div - 1) / instance_div;
97
            size = vb->stride * (count - 1) + elemSize;
98
         } else {
99
            first = vb->stride * start + ve[i].src_offset;
100
            size = vb->stride * (count - 1) + elemSize;
101
         }
102
 
103
         buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
104
         buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
105
      }
106
   }
107
}
108
 
109
 
110
/**
111
 * svga_upload_user_buffers - upload parts of user buffers
112
 *
113
 * This function streams a part of a user buffer to hw and fills
114
 * svga_buffer::uploaded with information on the upload.
115
 */
116
static int
117
svga_upload_user_buffers(struct svga_context *svga,
118
                         unsigned start,
119
                         unsigned count,
120
                         unsigned instance_count)
121
{
122
   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
123
   unsigned i;
124
   int ret;
125
 
126
   svga_user_buffer_range(svga, start, count, instance_count);
127
 
128
   for (i=0; i < svga->curr.velems->count; i++) {
129
      struct pipe_vertex_buffer *vb =
130
         &svga->curr.vb[ve[i].vertex_buffer_index];
131
 
132
      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
133
         struct svga_buffer *buffer = svga_buffer(vb->buffer);
134
 
135
         /*
136
          * Check if already uploaded. Otherwise go ahead and upload.
137
          */
138
 
139
         if (buffer->uploaded.buffer)
140
            continue;
141
 
142
         ret = u_upload_buffer( svga->upload_vb,
143
                                0,
144
                                buffer->uploaded.start,
145
                                buffer->uploaded.end - buffer->uploaded.start,
146
                                &buffer->b.b,
147
                                &buffer->uploaded.offset,
148
                                &buffer->uploaded.buffer);
149
 
150
         if (ret)
151
            return ret;
152
 
153
         if (0)
154
            debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d"
155
                         " sz %d\n",
156
                         __FUNCTION__,
157
                         i,
158
                         buffer,
159
                         buffer->uploaded.buffer,
160
                         buffer->uploaded.offset,
161
                         buffer->uploaded.start,
162
                         buffer->uploaded.end - buffer->uploaded.start);
163
 
164
         vb->buffer_offset = buffer->uploaded.offset;
165
      }
166
   }
167
 
168
   return PIPE_OK;
169
}
170
 
171
 
172
/**
173
 * svga_release_user_upl_buffers - release uploaded parts of user buffers
174
 *
175
 * This function releases the hw copy of the uploaded fraction of the
176
 * user-buffer. It's important to do this as soon as all draw calls
177
 * affecting the uploaded fraction are issued, as this allows for
178
 * efficient reuse of the hardware surface backing the uploaded fraction.
179
 *
180
 * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer
181
 * is set to 0.
182
 */
183
static void
184
svga_release_user_upl_buffers(struct svga_context *svga)
185
{
186
   unsigned i;
187
   unsigned nr;
188
 
189
   nr = svga->curr.num_vertex_buffers;
190
 
191
   for (i = 0; i < nr; ++i) {
192
      struct pipe_vertex_buffer *vb = &svga->curr.vb[i];
193
 
194
      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
195
         struct svga_buffer *buffer = svga_buffer(vb->buffer);
196
 
197
         /* The buffer_offset is relative to the uploaded buffer.
198
          * Since we're discarding that buffer we need to reset this offset
199
          * so it's not inadvertantly applied to a subsequent draw.
200
          *
201
          * XXX a root problem here is that the svga->curr.vb[] information
202
          * is getting set both by gallium API calls and by code in
203
          * svga_upload_user_buffers().  We should instead have two copies
204
          * of the vertex buffer information and choose between as needed.
205
          */
206
         vb->buffer_offset = 0;
207
 
208
         buffer->uploaded.start = ~0;
209
         buffer->uploaded.end = 0;
210
         if (buffer->uploaded.buffer)
211
            pipe_resource_reference(&buffer->uploaded.buffer, NULL);
212
      }
213
   }
214
}
215
 
216
 
217
 
218
static enum pipe_error
219
retry_draw_range_elements( struct svga_context *svga,
220
                           struct pipe_resource *index_buffer,
221
                           unsigned index_size,
222
                           int index_bias,
223
                           unsigned min_index,
224
                           unsigned max_index,
225
                           unsigned prim,
226
                           unsigned start,
227
                           unsigned count,
228
                           unsigned instance_count,
229
                           boolean do_retry )
230
{
231
   enum pipe_error ret = PIPE_OK;
232
 
233
   svga_hwtnl_set_unfilled( svga->hwtnl,
234
                            svga->curr.rast->hw_unfilled );
235
 
236
   svga_hwtnl_set_flatshade( svga->hwtnl,
237
                             svga->curr.rast->templ.flatshade,
238
                             svga->curr.rast->templ.flatshade_first );
239
 
240
   ret = svga_upload_user_buffers( svga, min_index + index_bias,
241
                                   max_index - min_index + 1, instance_count );
242
   if (ret != PIPE_OK)
243
      goto retry;
244
 
245
   ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
246
   if (ret != PIPE_OK)
247
      goto retry;
248
 
249
   ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
250
                                         index_buffer, index_size, index_bias,
251
                                         min_index, max_index,
252
                                         prim, start, count );
253
   if (ret != PIPE_OK)
254
      goto retry;
255
 
256
   return PIPE_OK;
257
 
258
retry:
259
   svga_context_flush( svga, NULL );
260
 
261
   if (do_retry)
262
   {
263
      return retry_draw_range_elements( svga,
264
                                        index_buffer, index_size, index_bias,
265
                                        min_index, max_index,
266
                                        prim, start, count,
267
                                        instance_count, FALSE );
268
   }
269
 
270
   return ret;
271
}
272
 
273
 
274
static enum pipe_error
275
retry_draw_arrays( struct svga_context *svga,
276
                   unsigned prim,
277
                   unsigned start,
278
                   unsigned count,
279
                   unsigned instance_count,
280
                   boolean do_retry )
281
{
282
   enum pipe_error ret;
283
 
284
   svga_hwtnl_set_unfilled( svga->hwtnl,
285
                            svga->curr.rast->hw_unfilled );
286
 
287
   svga_hwtnl_set_flatshade( svga->hwtnl,
288
                             svga->curr.rast->templ.flatshade,
289
                             svga->curr.rast->templ.flatshade_first );
290
 
291
   ret = svga_upload_user_buffers( svga, start, count, instance_count );
292
 
293
   if (ret != PIPE_OK)
294
      goto retry;
295
 
296
   ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
297
   if (ret != PIPE_OK)
298
      goto retry;
299
 
300
   ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
301
                                 start, count );
302
   if (ret != PIPE_OK)
303
      goto retry;
304
 
305
   return PIPE_OK;
306
 
307
retry:
308
   if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
309
   {
310
      svga_context_flush( svga, NULL );
311
 
312
      return retry_draw_arrays( svga,
313
                                prim,
314
                                start,
315
                                count,
316
                                instance_count,
317
                                FALSE );
318
   }
319
 
320
   return ret;
321
}
322
 
323
 
324
static void
325
svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
326
{
327
   struct svga_context *svga = svga_context( pipe );
328
   unsigned reduced_prim = u_reduced_prim( info->mode );
329
   unsigned count = info->count;
330
   enum pipe_error ret = 0;
331
   boolean needed_swtnl;
332
 
333
   svga->num_draw_calls++;  /* for SVGA_QUERY_DRAW_CALLS */
334
 
335
   if (!u_trim_pipe_prim( info->mode, &count ))
336
      return;
337
 
338
   /*
339
    * Mark currently bound target surfaces as dirty
340
    * doesn't really matter if it is done before drawing.
341
    *
342
    * TODO If we ever normaly return something other then
343
    * true we should not mark it as dirty then.
344
    */
345
   svga_mark_surfaces_dirty(svga_context(pipe));
346
 
347
   if (svga->curr.reduced_prim != reduced_prim) {
348
      svga->curr.reduced_prim = reduced_prim;
349
      svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
350
   }
351
 
352
   needed_swtnl = svga->state.sw.need_swtnl;
353
 
354
   svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
355
 
356
#ifdef DEBUG
357
   if (svga->curr.vs->base.id == svga->debug.disable_shader ||
358
       svga->curr.fs->base.id == svga->debug.disable_shader)
359
      return;
360
#endif
361
 
362
   if (svga->state.sw.need_swtnl) {
363
      svga->num_fallbacks++;  /* for SVGA_QUERY_FALLBACKS */
364
      if (!needed_swtnl) {
365
         /*
366
          * We're switching from HW to SW TNL.  SW TNL will require mapping all
367
          * currently bound vertex buffers, some of which may already be
368
          * referenced in the current command buffer as result of previous HW
369
          * TNL. So flush now, to prevent the context to flush while a referred
370
          * vertex buffer is mapped.
371
          */
372
 
373
         svga_context_flush(svga, NULL);
374
      }
375
 
376
      /* Avoid leaking the previous hwtnl bias to swtnl */
377
      svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
378
      ret = svga_swtnl_draw_vbo( svga, info );
379
   }
380
   else {
381
      if (info->indexed && svga->curr.ib.buffer) {
382
         unsigned offset;
383
 
384
         assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
385
         offset = svga->curr.ib.offset / svga->curr.ib.index_size;
386
 
387
         ret = retry_draw_range_elements( svga,
388
                                          svga->curr.ib.buffer,
389
                                          svga->curr.ib.index_size,
390
                                          info->index_bias,
391
                                          info->min_index,
392
                                          info->max_index,
393
                                          info->mode,
394
                                          info->start + offset,
395
                                          info->count,
396
                                          info->instance_count,
397
                                          TRUE );
398
      }
399
      else {
400
         ret = retry_draw_arrays( svga,
401
                                  info->mode,
402
                                  info->start,
403
                                  info->count,
404
                                  info->instance_count,
405
                                  TRUE );
406
      }
407
   }
408
 
409
   /* XXX: Silence warnings, do something sensible here? */
410
   (void)ret;
411
 
412
   svga_release_user_upl_buffers( svga );
413
 
414
   if (SVGA_DEBUG & DEBUG_FLUSH) {
415
      svga_hwtnl_flush_retry( svga );
416
      svga_context_flush(svga, NULL);
417
   }
418
}
419
 
420
 
421
void svga_init_draw_functions( struct svga_context *svga )
422
{
423
   svga->pipe.draw_vbo = svga_draw_vbo;
424
}