• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * \file
30  * Vertex buffer drawing stage.
31  *
32  * \author Jose Fonseca <jfonseca@vmware.com>
33  * \author Keith Whitwell <keithw@vmware.com>
34  */
35 
36 
37 #include "util/u_debug.h"
38 #include "util/u_math.h"
39 #include "util/u_memory.h"
40 
41 #include "draw_vbuf.h"
42 #include "draw_private.h"
43 #include "draw_vertex.h"
44 #include "draw_pipe.h"
45 #include "translate/translate.h"
46 #include "translate/translate_cache.h"
47 
48 
49 /**
50  * Vertex buffer emit stage.
51  */
52 struct vbuf_stage {
53    struct draw_stage stage; /**< This must be first (base class) */
54 
55    struct vbuf_render *render;
56 
57    const struct vertex_info *vinfo;
58 
59    /** Vertex size in bytes */
60    unsigned vertex_size;
61 
62    struct translate *translate;
63 
64    /* FIXME: we have no guarantee that 'unsigned' is 32bit */
65 
66    /** Vertices in hardware format */
67    unsigned *vertices;
68    unsigned *vertex_ptr;
69    unsigned max_vertices;
70    unsigned nr_vertices;
71 
72    /** Indices */
73    ushort *indices;
74    unsigned max_indices;
75    unsigned nr_indices;
76 
77    /* Cache point size somewhere its address won't change:
78     */
79    float point_size;
80    float zero4[4];
81 
82    struct translate_cache *cache;
83 };
84 
85 
86 /**
87  * Basically a cast wrapper.
88  */
89 static inline struct vbuf_stage *
vbuf_stage(struct draw_stage * stage)90 vbuf_stage( struct draw_stage *stage )
91 {
92    assert(stage);
93    return (struct vbuf_stage *)stage;
94 }
95 
96 
97 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
98 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
99 
100 
101 static inline boolean
overflow(void * map,void * ptr,unsigned bytes,unsigned bufsz)102 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
103 {
104    unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
105    return (used + bytes) > bufsz;
106 }
107 
108 
109 static inline void
check_space(struct vbuf_stage * vbuf,unsigned nr)110 check_space( struct vbuf_stage *vbuf, unsigned nr )
111 {
112    if (vbuf->nr_vertices + nr > vbuf->max_vertices ||
113        vbuf->nr_indices + nr > vbuf->max_indices)
114    {
115       vbuf_flush_vertices( vbuf );
116       vbuf_alloc_vertices( vbuf );
117    }
118 }
119 
120 
121 
122 
123 /**
124  * Extract the needed fields from post-transformed vertex and emit
125  * a hardware(driver) vertex.
126  * Recall that the vertices are constructed by the 'draw' module and
127  * have a couple of slots at the beginning (1-dword header, 4-dword
128  * clip pos) that we ignore here.  We only use the vertex->data[] fields.
129  */
130 static inline ushort
emit_vertex(struct vbuf_stage * vbuf,struct vertex_header * vertex)131 emit_vertex( struct vbuf_stage *vbuf,
132              struct vertex_header *vertex )
133 {
134    if (vertex->vertex_id == UNDEFINED_VERTEX_ID && vbuf->vertex_ptr) {
135       /* Hmm - vertices are emitted one at a time - better make sure
136        * set_buffer is efficient.  Consider a special one-shot mode for
137        * translate.
138        */
139       /* Note: we really do want data[0] here, not data[pos]:
140        */
141       vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0, ~0);
142       vbuf->translate->run(vbuf->translate, 0, 1, 0, 0, vbuf->vertex_ptr);
143 
144       if (0) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
145 
146       vbuf->vertex_ptr += vbuf->vertex_size/4;
147       vertex->vertex_id = vbuf->nr_vertices++;
148    }
149 
150    return (ushort)vertex->vertex_id;
151 }
152 
153 
154 static void
vbuf_tri(struct draw_stage * stage,struct prim_header * prim)155 vbuf_tri( struct draw_stage *stage,
156           struct prim_header *prim )
157 {
158    struct vbuf_stage *vbuf = vbuf_stage( stage );
159    unsigned i;
160 
161    check_space( vbuf, 3 );
162 
163    for (i = 0; i < 3; i++) {
164       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
165    }
166 }
167 
168 
169 static void
vbuf_line(struct draw_stage * stage,struct prim_header * prim)170 vbuf_line( struct draw_stage *stage,
171            struct prim_header *prim )
172 {
173    struct vbuf_stage *vbuf = vbuf_stage( stage );
174    unsigned i;
175 
176    check_space( vbuf, 2 );
177 
178    for (i = 0; i < 2; i++) {
179       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
180    }
181 }
182 
183 
184 static void
vbuf_point(struct draw_stage * stage,struct prim_header * prim)185 vbuf_point( struct draw_stage *stage,
186             struct prim_header *prim )
187 {
188    struct vbuf_stage *vbuf = vbuf_stage( stage );
189 
190    check_space( vbuf, 1 );
191 
192    vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
193 }
194 
195 
196 
197 
198 /**
199  * Set the prim type for subsequent vertices.
200  * This may result in a new vertex size.  The existing vbuffer (if any)
201  * will be flushed if needed and a new one allocated.
202  */
203 static void
vbuf_start_prim(struct vbuf_stage * vbuf,uint prim)204 vbuf_start_prim( struct vbuf_stage *vbuf, uint prim )
205 {
206    struct translate_key hw_key;
207    unsigned dst_offset;
208    unsigned i;
209    const struct vertex_info *vinfo;
210 
211    vbuf->render->set_primitive(vbuf->render, prim);
212 
213    /* Must do this after set_primitive() above:
214     *
215     * XXX: need some state managment to track when this needs to be
216     * recalculated.  The driver should tell us whether there was a
217     * state change.
218     */
219    vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
220    vinfo = vbuf->vinfo;
221    vbuf->vertex_size = vinfo->size * sizeof(float);
222 
223    /* Translate from pipeline vertices to hw vertices.
224     */
225    dst_offset = 0;
226 
227    for (i = 0; i < vinfo->num_attribs; i++) {
228       unsigned emit_sz = 0;
229       unsigned src_buffer = 0;
230       enum pipe_format output_format;
231       unsigned src_offset = (vinfo->attrib[i].src_index * 4 * sizeof(float) );
232 
233       output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
234       emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
235 
236       /* doesn't handle EMIT_OMIT */
237       assert(emit_sz != 0);
238 
239       if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
240          src_buffer = 1;
241          src_offset = 0;
242       }
243       else if (vinfo->attrib[i].src_index == DRAW_ATTR_NONEXIST) {
244          /* elements which don't exist will get assigned zeros */
245          src_buffer = 2;
246          src_offset = 0;
247       }
248 
249       hw_key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
250       hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
251       hw_key.element[i].input_buffer = src_buffer;
252       hw_key.element[i].input_offset = src_offset;
253       hw_key.element[i].instance_divisor = 0;
254       hw_key.element[i].output_format = output_format;
255       hw_key.element[i].output_offset = dst_offset;
256 
257       dst_offset += emit_sz;
258    }
259 
260    hw_key.nr_elements = vinfo->num_attribs;
261    hw_key.output_stride = vbuf->vertex_size;
262 
263    /* Don't bother with caching at this stage:
264     */
265    if (!vbuf->translate ||
266        translate_key_compare(&vbuf->translate->key, &hw_key) != 0)
267    {
268       translate_key_sanitize(&hw_key);
269       vbuf->translate = translate_cache_find(vbuf->cache, &hw_key);
270 
271       vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0, ~0);
272       vbuf->translate->set_buffer(vbuf->translate, 2, &vbuf->zero4[0], 0, ~0);
273    }
274 
275    vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
276 
277    /* Allocate new buffer?
278     */
279    assert(vbuf->vertices == NULL);
280    vbuf_alloc_vertices(vbuf);
281 }
282 
283 
284 static void
vbuf_first_tri(struct draw_stage * stage,struct prim_header * prim)285 vbuf_first_tri( struct draw_stage *stage,
286                 struct prim_header *prim )
287 {
288    struct vbuf_stage *vbuf = vbuf_stage( stage );
289 
290    vbuf_flush_vertices( vbuf );
291    vbuf_start_prim(vbuf, PIPE_PRIM_TRIANGLES);
292    stage->tri = vbuf_tri;
293    stage->tri( stage, prim );
294 }
295 
296 
297 static void
vbuf_first_line(struct draw_stage * stage,struct prim_header * prim)298 vbuf_first_line( struct draw_stage *stage,
299                  struct prim_header *prim )
300 {
301    struct vbuf_stage *vbuf = vbuf_stage( stage );
302 
303    vbuf_flush_vertices( vbuf );
304    vbuf_start_prim(vbuf, PIPE_PRIM_LINES);
305    stage->line = vbuf_line;
306    stage->line( stage, prim );
307 }
308 
309 
310 static void
vbuf_first_point(struct draw_stage * stage,struct prim_header * prim)311 vbuf_first_point( struct draw_stage *stage,
312                   struct prim_header *prim )
313 {
314    struct vbuf_stage *vbuf = vbuf_stage( stage );
315 
316    vbuf_flush_vertices(vbuf);
317    vbuf_start_prim(vbuf, PIPE_PRIM_POINTS);
318    stage->point = vbuf_point;
319    stage->point( stage, prim );
320 }
321 
322 
323 
324 /**
325  * Flush existing vertex buffer and allocate a new one.
326  */
327 static void
vbuf_flush_vertices(struct vbuf_stage * vbuf)328 vbuf_flush_vertices( struct vbuf_stage *vbuf )
329 {
330    if(vbuf->vertices) {
331 
332       vbuf->render->unmap_vertices( vbuf->render, 0, vbuf->nr_vertices - 1 );
333 
334       if (vbuf->nr_indices)
335       {
336          vbuf->render->draw_elements(vbuf->render,
337                                      vbuf->indices,
338                                      vbuf->nr_indices );
339 
340          vbuf->nr_indices = 0;
341       }
342 
343       /* Reset temporary vertices ids */
344       if(vbuf->nr_vertices)
345 	 draw_reset_vertex_ids( vbuf->stage.draw );
346 
347       /* Free the vertex buffer */
348       vbuf->render->release_vertices( vbuf->render );
349 
350       vbuf->max_vertices = vbuf->nr_vertices = 0;
351       vbuf->vertex_ptr = vbuf->vertices = NULL;
352    }
353 
354    /* Reset point/line/tri function pointers.
355     * If (for example) we transition from points to tris and back to points
356     * again, we need to call the vbuf_first_point() function again to flush
357     * the triangles before drawing more points.  This can happen when drawing
358     * with front polygon mode = filled and back polygon mode = line or point.
359     */
360    vbuf->stage.point = vbuf_first_point;
361    vbuf->stage.line = vbuf_first_line;
362    vbuf->stage.tri = vbuf_first_tri;
363 }
364 
365 
366 static void
vbuf_alloc_vertices(struct vbuf_stage * vbuf)367 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
368 {
369    if (vbuf->vertex_ptr) {
370       assert(!vbuf->nr_indices);
371       assert(!vbuf->vertices);
372    }
373 
374    /* Allocate a new vertex buffer */
375    vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
376 
377    if(vbuf->max_vertices >= UNDEFINED_VERTEX_ID)
378       vbuf->max_vertices = UNDEFINED_VERTEX_ID - 1;
379 
380    /* Must always succeed -- driver gives us a
381     * 'max_vertex_buffer_bytes' which it guarantees it can allocate,
382     * and it will flush itself if necessary to do so.  If this does
383     * fail, we are basically without usable hardware.
384     */
385    vbuf->render->allocate_vertices(vbuf->render,
386                                    (ushort) vbuf->vertex_size,
387                                    (ushort) vbuf->max_vertices);
388 
389    vbuf->vertices = (uint *) vbuf->render->map_vertices( vbuf->render );
390 
391    vbuf->vertex_ptr = vbuf->vertices;
392 }
393 
394 
395 
396 static void
vbuf_flush(struct draw_stage * stage,unsigned flags)397 vbuf_flush( struct draw_stage *stage, unsigned flags )
398 {
399    struct vbuf_stage *vbuf = vbuf_stage( stage );
400 
401    vbuf_flush_vertices( vbuf );
402 }
403 
404 
405 static void
vbuf_reset_stipple_counter(struct draw_stage * stage)406 vbuf_reset_stipple_counter( struct draw_stage *stage )
407 {
408    /* XXX: Need to do something here for hardware with linestipple.
409     */
410    (void) stage;
411 }
412 
413 
vbuf_destroy(struct draw_stage * stage)414 static void vbuf_destroy( struct draw_stage *stage )
415 {
416    struct vbuf_stage *vbuf = vbuf_stage( stage );
417 
418    if(vbuf->indices)
419       align_free( vbuf->indices );
420 
421    if (vbuf->render)
422       vbuf->render->destroy( vbuf->render );
423 
424    if (vbuf->cache)
425       translate_cache_destroy(vbuf->cache);
426 
427    FREE( stage );
428 }
429 
430 
431 /**
432  * Create a new primitive vbuf/render stage.
433  */
draw_vbuf_stage(struct draw_context * draw,struct vbuf_render * render)434 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
435                                     struct vbuf_render *render )
436 {
437    struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
438    if (!vbuf)
439       goto fail;
440 
441    vbuf->stage.draw = draw;
442    vbuf->stage.name = "vbuf";
443    vbuf->stage.point = vbuf_first_point;
444    vbuf->stage.line = vbuf_first_line;
445    vbuf->stage.tri = vbuf_first_tri;
446    vbuf->stage.flush = vbuf_flush;
447    vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
448    vbuf->stage.destroy = vbuf_destroy;
449 
450    vbuf->render = render;
451    vbuf->max_indices = MIN2(render->max_indices, UNDEFINED_VERTEX_ID-1);
452 
453    vbuf->indices = (ushort *) align_malloc(vbuf->max_indices *
454                     sizeof(vbuf->indices[0]),
455                     16);
456    if (!vbuf->indices)
457       goto fail;
458 
459    vbuf->cache = translate_cache_create();
460    if (!vbuf->cache)
461       goto fail;
462 
463    vbuf->vertices = NULL;
464    vbuf->vertex_ptr = vbuf->vertices;
465 
466    vbuf->zero4[0] = vbuf->zero4[1] = vbuf->zero4[2] = vbuf->zero4[3] = 0.0f;
467 
468    return &vbuf->stage;
469 
470 fail:
471    if (vbuf)
472       vbuf_destroy(&vbuf->stage);
473 
474    return NULL;
475 }
476