Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_emit.c
1 /**************************************************************************
2  * 
3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.com>
31   */
32
33 #include "util/u_memory.h"
34 #include "draw/draw_context.h"
35 #include "draw/draw_private.h"
36 #include "draw/draw_vbuf.h"
37 #include "draw/draw_vertex.h"
38 #include "draw/draw_pt.h"
39 #include "draw/draw_gs.h"
40 #include "translate/translate.h"
41 #include "translate/translate_cache.h"
42
43 /* The simplest 'middle end' in the new vertex code.  
44  * 
45  * The responsibilities of a middle end are to:
46  *  - perform vertex fetch using
47  *       - draw vertex element/buffer state
48  *       - a list of fetch indices we received as an input
49  *  - run the vertex shader
50  *  - cliptest, 
51  *  - clip coord calculation 
52  *  - viewport transformation
53  *  - if necessary, run the primitive pipeline, passing it:
54  *       - a linear array of vertex_header vertices constructed here
55  *       - a set of draw indices we received as an input
56  *  - otherwise, drive the hw backend,
57  *       - allocate space for hardware format vertices
58  *       - translate the vertex-shader output vertices to hw format
59  *       - calling the backend draw functions.
60  *
61  * For convenience, we provide a helper function to drive the hardware
62  * backend given similar inputs to those required to run the pipeline.
63  *
64  * In the case of passthrough mode, many of these actions are disabled
65  * or noops, so we end up doing:
66  *
67  *  - perform vertex fetch
68  *  - drive the hw backend
69  *
70  * IE, basically just vertex fetch to post-vs-format vertices,
71  * followed by a call to the backend helper function.
72  */
73
74
75 struct fetch_emit_middle_end {
76    struct draw_pt_middle_end base;
77    struct draw_context *draw;
78    
79    struct translate *translate;
80    const struct vertex_info *vinfo;
81
82    /* Cache point size somewhere it's address won't change:
83     */
84    float point_size;
85
86    struct translate_cache *cache;
87 };
88
89
90
91
92 static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
93                                 unsigned prim,
94                                 unsigned opt,
95                                 unsigned *max_vertices )
96 {
97    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
98    struct draw_context *draw = feme->draw;
99    const struct vertex_info *vinfo;
100    unsigned i, dst_offset;
101    boolean ok;
102    struct translate_key key;
103
104    unsigned gs_out_prim = (draw->gs.geometry_shader ? 
105                            draw->gs.geometry_shader->output_primitive :
106                            prim);
107
108
109
110    ok = draw->render->set_primitive( draw->render, 
111                                      gs_out_prim );
112    if (!ok) {
113       assert(0);
114       return;
115    }
116    
117    /* Must do this after set_primitive() above:
118     */
119    vinfo = feme->vinfo = draw->render->get_vertex_info(draw->render);
120    
121    
122
123    /* Transform from API vertices to HW vertices, skipping the
124     * pipeline_vertex intermediate step.
125     */
126    dst_offset = 0;
127    memset(&key, 0, sizeof(key));
128
129    for (i = 0; i < vinfo->num_attribs; i++) {
130       const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->attrib[i].src_index];
131
132       unsigned emit_sz = 0;
133       unsigned input_format = src->src_format;
134       unsigned input_buffer = src->vertex_buffer_index;
135       unsigned input_offset = src->src_offset;
136       unsigned output_format;
137
138       output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
139       emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
140
141       if (vinfo->attrib[i].emit == EMIT_OMIT)
142          continue;
143
144       if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
145          input_format = PIPE_FORMAT_R32_FLOAT;
146          input_buffer = draw->pt.nr_vertex_buffers;
147          input_offset = 0;
148       }
149
150       key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
151       key.element[i].input_format = input_format;
152       key.element[i].input_buffer = input_buffer;
153       key.element[i].input_offset = input_offset;
154       key.element[i].instance_divisor = src->instance_divisor;
155       key.element[i].output_format = output_format;
156       key.element[i].output_offset = dst_offset;
157       
158       dst_offset += emit_sz;
159    }
160
161    key.nr_elements = vinfo->num_attribs;
162    key.output_stride = vinfo->size * 4;
163
164    /* Don't bother with caching at this stage:
165     */
166    if (!feme->translate ||
167        translate_key_compare(&feme->translate->key, &key) != 0) 
168    {
169       translate_key_sanitize(&key);
170       feme->translate = translate_cache_find(feme->cache,
171                                              &key);
172
173
174       feme->translate->set_buffer(feme->translate, 
175                                   draw->pt.nr_vertex_buffers, 
176                                   &feme->point_size,
177                                   0,
178                                   ~0);
179    }
180    
181    feme->point_size = draw->rasterizer->point_size;
182
183    for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
184       feme->translate->set_buffer(feme->translate, 
185                                   i, 
186                                   ((char *)draw->pt.user.vbuffer[i] + 
187                                    draw->pt.vertex_buffer[i].buffer_offset),
188                                   draw->pt.vertex_buffer[i].stride,
189                                   draw->pt.max_index);
190    }
191
192    *max_vertices = (draw->render->max_vertex_buffer_bytes / 
193                     (vinfo->size * 4));
194 }
195
196
197
198
199
200 static void fetch_emit_run( struct draw_pt_middle_end *middle,
201                             const unsigned *fetch_elts,
202                             unsigned fetch_count,
203                             const ushort *draw_elts,
204                             unsigned draw_count,
205                             unsigned prim_flags )
206 {
207    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
208    struct draw_context *draw = feme->draw;
209    void *hw_verts;
210    
211    /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 
212     */
213    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
214
215    draw->render->allocate_vertices( draw->render,
216                                     (ushort)feme->translate->key.output_stride,
217                                     (ushort)fetch_count );
218
219    hw_verts = draw->render->map_vertices( draw->render );
220    if (!hw_verts) {
221       assert(0);
222       return;
223    }
224          
225                                         
226    /* Single routine to fetch vertices and emit HW verts.
227     */
228    feme->translate->run_elts( feme->translate, 
229                               fetch_elts,
230                               fetch_count,
231                               draw->instance_id,
232                               hw_verts );
233
234    if (0) {
235       unsigned i;
236       for (i = 0; i < fetch_count; i++) {
237          debug_printf("\n\nvertex %d:\n", i);
238          draw_dump_emitted_vertex( feme->vinfo, 
239                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
240       }
241    }
242
243    draw->render->unmap_vertices( draw->render, 
244                                  0, 
245                                  (ushort)(fetch_count - 1) );
246
247    /* XXX: Draw arrays path to avoid re-emitting index list again and
248     * again.
249     */
250    draw->render->draw_elements( draw->render, 
251                                 draw_elts, 
252                                 draw_count );
253
254    /* Done -- that was easy, wasn't it: 
255     */
256    draw->render->release_vertices( draw->render );
257
258 }
259
260
261 static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
262                                    unsigned start,
263                                    unsigned count,
264                                    unsigned prim_flags )
265 {
266    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
267    struct draw_context *draw = feme->draw;
268    void *hw_verts;
269
270    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
271     */
272    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
273
274    if (!draw->render->allocate_vertices( draw->render,
275                                          (ushort)feme->translate->key.output_stride,
276                                          (ushort)count )) 
277       goto fail;
278
279    hw_verts = draw->render->map_vertices( draw->render );
280    if (!hw_verts) 
281       goto fail;
282
283    /* Single routine to fetch vertices and emit HW verts.
284     */
285    feme->translate->run( feme->translate,
286                          start,
287                          count,
288                          draw->instance_id,
289                          hw_verts );
290
291    if (0) {
292       unsigned i;
293       for (i = 0; i < count; i++) {
294          debug_printf("\n\nvertex %d:\n", i);
295          draw_dump_emitted_vertex( feme->vinfo,
296                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
297       }
298    }
299
300    draw->render->unmap_vertices( draw->render, 0, count - 1 );
301
302    /* XXX: Draw arrays path to avoid re-emitting index list again and
303     * again.
304     */
305    draw->render->draw_arrays( draw->render, 0, count );
306
307    /* Done -- that was easy, wasn't it:
308     */
309    draw->render->release_vertices( draw->render );
310    return;
311
312 fail:
313    assert(0);
314    return;
315 }
316
317
318 static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
319                                         unsigned start,
320                                         unsigned count,
321                                         const ushort *draw_elts,
322                                         unsigned draw_count,
323                                         unsigned prim_flags )
324 {
325    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
326    struct draw_context *draw = feme->draw;
327    void *hw_verts;
328
329    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
330     */
331    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
332
333    if (!draw->render->allocate_vertices( draw->render,
334                                          (ushort)feme->translate->key.output_stride,
335                                          (ushort)count ))
336       return FALSE;
337
338    hw_verts = draw->render->map_vertices( draw->render );
339    if (!hw_verts) 
340       return FALSE;
341
342    /* Single routine to fetch vertices and emit HW verts.
343     */
344    feme->translate->run( feme->translate,
345                          start,
346                          count,
347                          draw->instance_id,
348                          hw_verts );
349
350    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
351
352    /* XXX: Draw arrays path to avoid re-emitting index list again and
353     * again.
354     */
355    draw->render->draw_elements( draw->render, 
356                                 draw_elts, 
357                                 draw_count );
358
359    /* Done -- that was easy, wasn't it:
360     */
361    draw->render->release_vertices( draw->render );
362
363    return TRUE;
364 }
365
366
367
368
369 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
370 {
371    /* nothing to do */
372 }
373
374 static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
375 {
376    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
377
378    if (feme->cache)
379       translate_cache_destroy(feme->cache);
380
381    FREE(middle);
382 }
383
384
385 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
386 {
387    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
388    if (fetch_emit == NULL)
389       return NULL;
390
391    fetch_emit->cache = translate_cache_create();
392    if (!fetch_emit->cache) {
393       FREE(fetch_emit);
394       return NULL;
395    }
396
397    fetch_emit->base.prepare    = fetch_emit_prepare;
398    fetch_emit->base.run        = fetch_emit_run;
399    fetch_emit->base.run_linear = fetch_emit_run_linear;
400    fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
401    fetch_emit->base.finish     = fetch_emit_finish;
402    fetch_emit->base.destroy    = fetch_emit_destroy;
403
404    fetch_emit->draw = draw;
405      
406    return &fetch_emit->base;
407 }
408