Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/**************************************************************************
2
 *
3
 * Copyright 2007 VMware, Inc.
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
 
28
 /*
29
  * Authors:
30
  *   Keith Whitwell 
31
  */
32
 
33
#include "draw/draw_context.h"
34
#include "draw/draw_gs.h"
35
#include "draw/draw_private.h"
36
#include "draw/draw_pt.h"
37
#include "draw/draw_vbuf.h"
38
#include "draw/draw_vs.h"
39
#include "tgsi/tgsi_dump.h"
40
#include "util/u_math.h"
41
#include "util/u_prim.h"
42
#include "util/u_format.h"
43
#include "util/u_draw.h"
44
 
45
 
46
DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", FALSE)
47
DEBUG_GET_ONCE_BOOL_OPTION(draw_no_fse, "DRAW_NO_FSE", FALSE)
48
 
49
/* Overall we split things into:
50
 *     - frontend -- prepare fetch_elts, draw_elts - eg vsplit
51
 *     - middle   -- fetch, shade, cliptest, viewport
52
 *     - pipeline -- the prim pipeline: clipping, wide lines, etc
53
 *     - backend  -- the vbuf_render provided by the driver.
54
 */
55
static boolean
56
draw_pt_arrays(struct draw_context *draw,
57
               unsigned prim,
58
               unsigned start,
59
               unsigned count)
60
{
61
   struct draw_pt_front_end *frontend = NULL;
62
   struct draw_pt_middle_end *middle = NULL;
63
   unsigned opt = 0;
64
 
65
   /* Sanitize primitive length:
66
    */
67
   {
68
      unsigned first, incr;
69
      draw_pt_split_prim(prim, &first, &incr);
70
      count = draw_pt_trim_count(count, first, incr);
71
      if (count < first)
72
         return TRUE;
73
   }
74
 
75
   if (!draw->force_passthrough) {
76
      unsigned gs_out_prim = (draw->gs.geometry_shader ?
77
                              draw->gs.geometry_shader->output_primitive :
78
                              prim);
79
 
80
      if (!draw->render) {
81
         opt |= PT_PIPELINE;
82
      }
83
 
84
      if (draw_need_pipeline(draw,
85
                             draw->rasterizer,
86
                             gs_out_prim)) {
87
         opt |= PT_PIPELINE;
88
      }
89
 
90
      if ((draw->clip_xy ||
91
           draw->clip_z ||
92
           draw->clip_user) && !draw->pt.test_fse) {
93
         opt |= PT_CLIPTEST;
94
      }
95
 
96
      opt |= PT_SHADE;
97
   }
98
 
99
   if (draw->pt.middle.llvm) {
100
      middle = draw->pt.middle.llvm;
101
   } else {
102
      if (opt == 0)
103
         middle = draw->pt.middle.fetch_emit;
104
      else if (opt == PT_SHADE && !draw->pt.no_fse)
105
         middle = draw->pt.middle.fetch_shade_emit;
106
      else
107
         middle = draw->pt.middle.general;
108
   }
109
 
110
   frontend = draw->pt.frontend;
111
 
112
   if (frontend ) {
113
      if (draw->pt.prim != prim || draw->pt.opt != opt) {
114
         /* In certain conditions switching primitives requires us to flush
115
          * and validate the different stages. One example is when smooth
116
          * lines are active but first drawn with triangles and then with
117
          * lines.
118
          */
119
         draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
120
         frontend = NULL;
121
      } else if (draw->pt.eltSize != draw->pt.user.eltSize) {
122
         /* Flush draw state if eltSize changed.
123
          * This could be improved so only the frontend is flushed since it
124
          * converts all indices to ushorts and the fetch part of the middle
125
          * always prepares both linear and indexed.
126
          */
127
         frontend->flush( frontend, DRAW_FLUSH_STATE_CHANGE );
128
         frontend = NULL;
129
      }
130
   }
131
 
132
   if (!frontend) {
133
      frontend = draw->pt.front.vsplit;
134
 
135
      frontend->prepare( frontend, prim, middle, opt );
136
 
137
      draw->pt.frontend = frontend;
138
      draw->pt.eltSize = draw->pt.user.eltSize;
139
      draw->pt.prim = prim;
140
      draw->pt.opt = opt;
141
   }
142
 
143
   if (draw->pt.rebind_parameters) {
144
      /* update constants, viewport dims, clip planes, etc */
145
      middle->bind_parameters(middle);
146
      draw->pt.rebind_parameters = FALSE;
147
   }
148
 
149
   frontend->run( frontend, start, count );
150
 
151
   return TRUE;
152
}
153
 
154
void draw_pt_flush( struct draw_context *draw, unsigned flags )
155
{
156
   assert(flags);
157
 
158
   if (draw->pt.frontend) {
159
      draw->pt.frontend->flush( draw->pt.frontend, flags );
160
 
161
      /* don't prepare if we only are flushing the backend */
162
      if (flags & DRAW_FLUSH_STATE_CHANGE)
163
         draw->pt.frontend = NULL;
164
   }
165
 
166
   if (flags & DRAW_FLUSH_PARAMETER_CHANGE) {
167
      draw->pt.rebind_parameters = TRUE;
168
   }
169
}
170
 
171
 
172
 
173
boolean draw_pt_init( struct draw_context *draw )
174
{
175
   draw->pt.test_fse = debug_get_option_draw_fse();
176
   draw->pt.no_fse = debug_get_option_draw_no_fse();
177
 
178
   draw->pt.front.vsplit = draw_pt_vsplit(draw);
179
   if (!draw->pt.front.vsplit)
180
      return FALSE;
181
 
182
   draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw );
183
   if (!draw->pt.middle.fetch_emit)
184
      return FALSE;
185
 
186
   draw->pt.middle.fetch_shade_emit = draw_pt_middle_fse( draw );
187
   if (!draw->pt.middle.fetch_shade_emit)
188
      return FALSE;
189
 
190
   draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit( draw );
191
   if (!draw->pt.middle.general)
192
      return FALSE;
193
 
194
#if HAVE_LLVM
195
   if (draw->llvm)
196
      draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm( draw );
197
#endif
198
 
199
   return TRUE;
200
}
201
 
202
 
203
void draw_pt_destroy( struct draw_context *draw )
204
{
205
   if (draw->pt.middle.llvm) {
206
      draw->pt.middle.llvm->destroy( draw->pt.middle.llvm );
207
      draw->pt.middle.llvm = NULL;
208
   }
209
 
210
   if (draw->pt.middle.general) {
211
      draw->pt.middle.general->destroy( draw->pt.middle.general );
212
      draw->pt.middle.general = NULL;
213
   }
214
 
215
   if (draw->pt.middle.fetch_emit) {
216
      draw->pt.middle.fetch_emit->destroy( draw->pt.middle.fetch_emit );
217
      draw->pt.middle.fetch_emit = NULL;
218
   }
219
 
220
   if (draw->pt.middle.fetch_shade_emit) {
221
      draw->pt.middle.fetch_shade_emit->destroy( draw->pt.middle.fetch_shade_emit );
222
      draw->pt.middle.fetch_shade_emit = NULL;
223
   }
224
 
225
   if (draw->pt.front.vsplit) {
226
      draw->pt.front.vsplit->destroy( draw->pt.front.vsplit );
227
      draw->pt.front.vsplit = NULL;
228
   }
229
}
230
 
231
 
232
/**
233
 * Debug- print the first 'count' vertices.
234
 */
235
static void
236
draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count)
237
{
238
   uint i;
239
 
240
   debug_printf("Draw arrays(prim = %u, start = %u, count = %u)\n",
241
                prim, start, count);
242
 
243
   for (i = 0; i < count; i++) {
244
      uint ii = 0;
245
      uint j;
246
 
247
      if (draw->pt.user.eltSize) {
248
         /* indexed arrays */
249
 
250
         switch (draw->pt.user.eltSize) {
251
         case 1:
252
            {
253
               const ubyte *elem = (const ubyte *) draw->pt.user.elts;
254
               ii = elem[start + i];
255
            }
256
            break;
257
         case 2:
258
            {
259
               const ushort *elem = (const ushort *) draw->pt.user.elts;
260
               ii = elem[start + i];
261
            }
262
            break;
263
         case 4:
264
            {
265
               const uint *elem = (const uint *) draw->pt.user.elts;
266
               ii = elem[start + i];
267
            }
268
            break;
269
         default:
270
            assert(0);
271
            return;
272
         }
273
         ii += draw->pt.user.eltBias;
274
         debug_printf("Element[%u + %u] + %i -> Vertex %u:\n", start, i,
275
                      draw->pt.user.eltBias, ii);
276
      }
277
      else {
278
         /* non-indexed arrays */
279
         ii = start + i;
280
         debug_printf("Vertex %u:\n", ii);
281
      }
282
 
283
      for (j = 0; j < draw->pt.nr_vertex_elements; j++) {
284
         uint buf = draw->pt.vertex_element[j].vertex_buffer_index;
285
         ubyte *ptr = (ubyte *) draw->pt.user.vbuffer[buf].map;
286
 
287
         if (draw->pt.vertex_element[j].instance_divisor) {
288
            ii = draw->instance_id / draw->pt.vertex_element[j].instance_divisor;
289
         }
290
 
291
         ptr += draw->pt.vertex_buffer[buf].buffer_offset;
292
         ptr += draw->pt.vertex_buffer[buf].stride * ii;
293
         ptr += draw->pt.vertex_element[j].src_offset;
294
 
295
         debug_printf("  Attr %u: ", j);
296
         switch (draw->pt.vertex_element[j].src_format) {
297
         case PIPE_FORMAT_R32_FLOAT:
298
            {
299
               float *v = (float *) ptr;
300
               debug_printf("R %f  @ %p\n", v[0], (void *) v);
301
            }
302
            break;
303
         case PIPE_FORMAT_R32G32_FLOAT:
304
            {
305
               float *v = (float *) ptr;
306
               debug_printf("RG %f %f  @ %p\n", v[0], v[1], (void *) v);
307
            }
308
            break;
309
         case PIPE_FORMAT_R32G32B32_FLOAT:
310
            {
311
               float *v = (float *) ptr;
312
               debug_printf("RGB %f %f %f  @ %p\n", v[0], v[1], v[2], (void *) v);
313
            }
314
            break;
315
         case PIPE_FORMAT_R32G32B32A32_FLOAT:
316
            {
317
               float *v = (float *) ptr;
318
               debug_printf("RGBA %f %f %f %f  @ %p\n", v[0], v[1], v[2], v[3],
319
                            (void *) v);
320
            }
321
            break;
322
         case PIPE_FORMAT_B8G8R8A8_UNORM:
323
            {
324
               ubyte *u = (ubyte *) ptr;
325
               debug_printf("BGRA %d %d %d %d  @ %p\n", u[0], u[1], u[2], u[3],
326
                            (void *) u);
327
            }
328
            break;
329
         case PIPE_FORMAT_A8R8G8B8_UNORM:
330
            {
331
               ubyte *u = (ubyte *) ptr;
332
               debug_printf("ARGB %d %d %d %d  @ %p\n", u[0], u[1], u[2], u[3],
333
                            (void *) u);
334
            }
335
            break;
336
         default:
337
            debug_printf("other format %s (fix me)\n",
338
                     util_format_name(draw->pt.vertex_element[j].src_format));
339
         }
340
      }
341
   }
342
}
343
 
344
 
345
/** Helper code for below */
346
#define PRIM_RESTART_LOOP(elements) \
347
   do { \
348
      for (j = 0; j < count; j++) {               \
349
         i = draw_overflow_uadd(start, j, MAX_LOOP_IDX);  \
350
         if (i < elt_max && elements[i] == info->restart_index) { \
351
            if (cur_count > 0) { \
352
               /* draw elts up to prev pos */ \
353
               draw_pt_arrays(draw, prim, cur_start, cur_count); \
354
            } \
355
            /* begin new prim at next elt */ \
356
            cur_start = i + 1; \
357
            cur_count = 0; \
358
         } \
359
         else { \
360
            cur_count++; \
361
         } \
362
      } \
363
      if (cur_count > 0) { \
364
         draw_pt_arrays(draw, prim, cur_start, cur_count); \
365
      } \
366
   } while (0)
367
 
368
 
369
/**
370
 * For drawing prims with primitive restart enabled.
371
 * Scan for restart indexes and draw the runs of elements/vertices between
372
 * the restarts.
373
 */
374
static void
375
draw_pt_arrays_restart(struct draw_context *draw,
376
                       const struct pipe_draw_info *info)
377
{
378
   const unsigned prim = info->mode;
379
   const unsigned start = info->start;
380
   const unsigned count = info->count;
381
   const unsigned elt_max = draw->pt.user.eltMax;
382
   unsigned i, j, cur_start, cur_count;
383
   /* The largest index within a loop using the i variable as the index.
384
    * Used for overflow detection */
385
   const unsigned MAX_LOOP_IDX = 0xffffffff;
386
 
387
   assert(info->primitive_restart);
388
 
389
   if (draw->pt.user.eltSize) {
390
      /* indexed prims (draw_elements) */
391
      cur_start = start;
392
      cur_count = 0;
393
 
394
      switch (draw->pt.user.eltSize) {
395
      case 1:
396
         {
397
            const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts;
398
            PRIM_RESTART_LOOP(elt_ub);
399
         }
400
         break;
401
      case 2:
402
         {
403
            const ushort *elt_us = (const ushort *) draw->pt.user.elts;
404
            PRIM_RESTART_LOOP(elt_us);
405
         }
406
         break;
407
      case 4:
408
         {
409
            const uint *elt_ui = (const uint *) draw->pt.user.elts;
410
            PRIM_RESTART_LOOP(elt_ui);
411
         }
412
         break;
413
      default:
414
         assert(0 && "bad eltSize in draw_arrays()");
415
      }
416
   }
417
   else {
418
      /* Non-indexed prims (draw_arrays).
419
       * Primitive restart should have been handled in the state tracker.
420
       */
421
      draw_pt_arrays(draw, prim, start, count);
422
   }
423
}
424
 
425
 
426
/**
427
 * Resolve true values within pipe_draw_info.
428
 * If we're rendering from transform feedback/stream output
429
 * buffers both the count and max_index need to be computed
430
 * from the attached stream output target.
431
 */
432
static void
433
resolve_draw_info(const struct pipe_draw_info *raw_info,
434
                  struct pipe_draw_info *info,
435
                  struct pipe_vertex_buffer *vertex_buffer)
436
{
437
   memcpy(info, raw_info, sizeof(struct pipe_draw_info));
438
 
439
   if (raw_info->count_from_stream_output) {
440
      struct draw_so_target *target =
441
         (struct draw_so_target *)info->count_from_stream_output;
442
      assert(vertex_buffer != NULL);
443
      info->count = target->internal_offset / vertex_buffer->stride;
444
 
445
      /* Stream output draw can not be indexed */
446
      debug_assert(!info->indexed);
447
      info->max_index = info->count - 1;
448
   }
449
}
450
 
451
/**
452
 * Draw vertex arrays.
453
 * This is the main entrypoint into the drawing module.  If drawing an indexed
454
 * primitive, the draw_set_indexes() function should have already been called
455
 * to specify the element/index buffer information.
456
 */
457
void
458
draw_vbo(struct draw_context *draw,
459
         const struct pipe_draw_info *info)
460
{
461
   unsigned instance;
462
   unsigned index_limit;
463
   unsigned count;
464
   unsigned fpstate = util_fpstate_get();
465
   struct pipe_draw_info resolved_info;
466
 
467
   /* Make sure that denorms are treated like zeros. This is
468
    * the behavior required by D3D10. OpenGL doesn't care.
469
    */
470
   util_fpstate_set_denorms_to_zero(fpstate);
471
 
472
   resolve_draw_info(info, &resolved_info, &(draw->pt.vertex_buffer[0]));
473
   info = &resolved_info;
474
 
475
   assert(info->instance_count > 0);
476
   if (info->indexed)
477
      assert(draw->pt.user.elts);
478
 
479
   count = info->count;
480
 
481
   draw->pt.user.eltBias = info->index_bias;
482
   draw->pt.user.min_index = info->min_index;
483
   draw->pt.user.max_index = info->max_index;
484
   draw->pt.user.eltSize = info->indexed ? draw->pt.user.eltSizeIB : 0;
485
 
486
   if (0)
487
      debug_printf("draw_vbo(mode=%u start=%u count=%u):\n",
488
                   info->mode, info->start, count);
489
 
490
   if (0)
491
      tgsi_dump(draw->vs.vertex_shader->state.tokens, 0);
492
 
493
   if (0) {
494
      unsigned int i;
495
      debug_printf("Elements:\n");
496
      for (i = 0; i < draw->pt.nr_vertex_elements; i++) {
497
         debug_printf("  %u: src_offset=%u  inst_div=%u   vbuf=%u  format=%s\n",
498
                      i,
499
                      draw->pt.vertex_element[i].src_offset,
500
                      draw->pt.vertex_element[i].instance_divisor,
501
                      draw->pt.vertex_element[i].vertex_buffer_index,
502
                      util_format_name(draw->pt.vertex_element[i].src_format));
503
      }
504
      debug_printf("Buffers:\n");
505
      for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
506
         debug_printf("  %u: stride=%u offset=%u size=%d ptr=%p\n",
507
                      i,
508
                      draw->pt.vertex_buffer[i].stride,
509
                      draw->pt.vertex_buffer[i].buffer_offset,
510
                      (int) draw->pt.user.vbuffer[i].size,
511
                      draw->pt.user.vbuffer[i].map);
512
      }
513
   }
514
 
515
   if (0)
516
      draw_print_arrays(draw, info->mode, info->start, MIN2(count, 20));
517
 
518
   index_limit = util_draw_max_index(draw->pt.vertex_buffer,
519
                                     draw->pt.vertex_element,
520
                                     draw->pt.nr_vertex_elements,
521
                                     info);
522
#if HAVE_LLVM
523
   if (!draw->llvm)
524
#endif
525
   {
526
      if (index_limit == 0) {
527
      /* one of the buffers is too small to do any valid drawing */
528
         debug_warning("draw: VBO too small to draw anything\n");
529
         util_fpstate_set(fpstate);
530
         return;
531
      }
532
   }
533
 
534
   /* If we're collecting stats then make sure we start from scratch */
535
   if (draw->collect_statistics) {
536
      memset(&draw->statistics, 0, sizeof(draw->statistics));
537
   }
538
 
539
   draw->pt.max_index = index_limit - 1;
540
   draw->start_index = info->start;
541
 
542
   /*
543
    * TODO: We could use draw->pt.max_index to further narrow
544
    * the min_index/max_index hints given by the state tracker.
545
    */
546
 
547
   for (instance = 0; instance < info->instance_count; instance++) {
548
      unsigned instance_idx = instance + info->start_instance;
549
      draw->start_instance = info->start_instance;
550
      draw->instance_id = instance;
551
      /* check for overflow */
552
      if (instance_idx < instance ||
553
          instance_idx < draw->start_instance) {
554
         /* if we overflown just set the instance id to the max */
555
         draw->instance_id = 0xffffffff;
556
      }
557
 
558
      draw_new_instance(draw);
559
 
560
      if (info->primitive_restart) {
561
         draw_pt_arrays_restart(draw, info);
562
      }
563
      else {
564
         draw_pt_arrays(draw, info->mode, info->start, count);
565
      }
566
   }
567
 
568
   /* If requested emit the pipeline statistics for this run */
569
   if (draw->collect_statistics) {
570
      draw->render->pipeline_statistics(draw->render, &draw->statistics);
571
   }
572
   util_fpstate_set(fpstate);
573
}