OSDN Git Service

draw: limit the number of vertex shader variants kept around
[android-x86/external-mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_shade_pipeline_llvm.c
1 /**************************************************************************
2  *
3  * Copyright 2010 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 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 #include "util/u_math.h"
29 #include "util/u_memory.h"
30 #include "draw/draw_context.h"
31 #include "draw/draw_gs.h"
32 #include "draw/draw_vbuf.h"
33 #include "draw/draw_vertex.h"
34 #include "draw/draw_pt.h"
35 #include "draw/draw_vs.h"
36 #include "draw/draw_llvm.h"
37
38
39 struct llvm_middle_end {
40    struct draw_pt_middle_end base;
41    struct draw_context *draw;
42
43    struct pt_emit *emit;
44    struct pt_so_emit *so_emit;
45    struct pt_fetch *fetch;
46    struct pt_post_vs *post_vs;
47
48
49    unsigned vertex_data_offset;
50    unsigned vertex_size;
51    unsigned input_prim;
52    unsigned opt;
53
54    struct draw_llvm *llvm;
55    struct draw_llvm_variant *current_variant;
56 };
57
58
59 static void
60 llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
61                          unsigned in_prim,
62                          unsigned opt,
63                          unsigned *max_vertices )
64 {
65    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
66    struct draw_context *draw = fpme->draw;
67    struct llvm_vertex_shader *shader =
68       llvm_vertex_shader(draw->vs.vertex_shader);
69    struct draw_llvm_variant_key key;
70    struct draw_llvm_variant *variant = NULL;
71    struct draw_llvm_variant_list_item *li;
72    unsigned i;
73    unsigned instance_id_index = ~0;
74
75
76    unsigned out_prim = (draw->gs.geometry_shader ? 
77                         draw->gs.geometry_shader->output_primitive :
78                         in_prim);
79
80    /* Add one to num_outputs because the pipeline occasionally tags on
81     * an additional texcoord, eg for AA lines.
82     */
83    unsigned nr = MAX2( shader->base.info.num_inputs,
84                        shader->base.info.num_outputs + 1 );
85
86    /* Scan for instanceID system value.
87     */
88    for (i = 0; i < shader->base.info.num_inputs; i++) {
89       if (shader->base.info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
90          instance_id_index = i;
91          break;
92       }
93    }
94
95    fpme->input_prim = in_prim;
96    fpme->opt = opt;
97
98    /* Always leave room for the vertex header whether we need it or
99     * not.  It's hard to get rid of it in particular because of the
100     * viewport code in draw_pt_post_vs.c.
101     */
102    fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
103
104
105    /* XXX: it's not really gl rasterization rules we care about here,
106     * but gl vs dx9 clip spaces.
107     */
108    draw_pt_post_vs_prepare( fpme->post_vs,
109                             (boolean)draw->bypass_clipping,
110                             (boolean)(draw->identity_viewport),
111                             (boolean)draw->rasterizer->gl_rasterization_rules,
112                             (draw->vs.edgeflag_output ? TRUE : FALSE) );
113
114    draw_pt_so_emit_prepare( fpme->so_emit );
115
116    if (!(opt & PT_PIPELINE)) {
117       draw_pt_emit_prepare( fpme->emit,
118                             out_prim,
119                             max_vertices );
120
121       *max_vertices = MAX2( *max_vertices,
122                             DRAW_PIPE_MAX_VERTICES );
123    }
124    else {
125       *max_vertices = DRAW_PIPE_MAX_VERTICES;
126    }
127
128    /* return even number */
129    *max_vertices = *max_vertices & ~1;
130
131    draw_llvm_make_variant_key(fpme->llvm, &key);
132
133    li = first_elem(&shader->variants);
134    while(!at_end(&shader->variants, li)) {
135       if(memcmp(&li->base->key, &key, sizeof key) == 0) {
136          variant = li->base;
137          break;
138       }
139       li = next_elem(li);
140    }
141
142    if (variant) {
143       move_to_head(&fpme->llvm->vs_variants_list, &variant->list_item_global);
144    }
145    else {
146       unsigned i;
147       if (fpme->llvm->nr_variants >= DRAW_MAX_SHADER_VARIANTS) {
148          /*
149           * XXX: should we flush here ?
150           */
151          for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 4; i++) {
152             struct draw_llvm_variant_list_item *item =
153                last_elem(&fpme->llvm->vs_variants_list);
154             draw_llvm_destroy_variant(item->base);
155          }
156       }
157
158       variant = draw_llvm_create_variant(fpme->llvm, nr);
159
160       if (variant) {
161          insert_at_head(&shader->variants, &variant->list_item_local);
162          insert_at_head(&fpme->llvm->vs_variants_list, &variant->list_item_global);
163          fpme->llvm->nr_variants++;
164          shader->variants_cached++;
165       }
166    }
167
168    fpme->current_variant = variant;
169
170    /*XXX we only support one constant buffer */
171    fpme->llvm->jit_context.vs_constants =
172       draw->pt.user.vs_constants[0];
173    fpme->llvm->jit_context.gs_constants =
174       draw->pt.user.gs_constants[0];
175 }
176
177
178 static void pipeline(struct llvm_middle_end *llvm,
179                      const struct draw_vertex_info *vert_info,
180                      const struct draw_prim_info *prim_info)
181 {
182    if (prim_info->linear)
183       draw_pipeline_run_linear( llvm->draw,
184                                 vert_info,
185                                 prim_info);
186    else
187       draw_pipeline_run( llvm->draw,
188                          vert_info,
189                          prim_info );
190 }
191
192 static void emit(struct pt_emit *emit,
193                  const struct draw_vertex_info *vert_info,
194                  const struct draw_prim_info *prim_info)
195 {
196    if (prim_info->linear) {
197       draw_pt_emit_linear(emit, vert_info, prim_info);
198    }
199    else {
200       draw_pt_emit(emit, vert_info, prim_info);
201    }
202 }
203
204 static void
205 llvm_pipeline_generic( struct draw_pt_middle_end *middle,
206                        const struct draw_fetch_info *fetch_info,
207                        const struct draw_prim_info *prim_info )
208 {
209    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
210    struct draw_context *draw = fpme->draw;
211    struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
212    struct draw_prim_info gs_prim_info;
213    struct draw_vertex_info llvm_vert_info;
214    struct draw_vertex_info gs_vert_info;
215    struct draw_vertex_info *vert_info;
216    unsigned opt = fpme->opt;
217
218    llvm_vert_info.count = fetch_info->count;
219    llvm_vert_info.vertex_size = fpme->vertex_size;
220    llvm_vert_info.stride = fpme->vertex_size;
221    llvm_vert_info.verts =
222       (struct vertex_header *)MALLOC(fpme->vertex_size *
223                                      align(fetch_info->count,  4));
224    if (!llvm_vert_info.verts) {
225       assert(0);
226       return;
227    }
228
229    if (fetch_info->linear)
230       fpme->current_variant->jit_func( &fpme->llvm->jit_context,
231                                        llvm_vert_info.verts,
232                                        (const char **)draw->pt.user.vbuffer,
233                                        fetch_info->start,
234                                        fetch_info->count,
235                                        fpme->vertex_size,
236                                        draw->pt.vertex_buffer );
237    else
238       fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
239                                             llvm_vert_info.verts,
240                                             (const char **)draw->pt.user.vbuffer,
241                                             fetch_info->elts,
242                                             fetch_info->count,
243                                             fpme->vertex_size,
244                                             draw->pt.vertex_buffer);
245
246    /* Finished with fetch and vs:
247     */
248    fetch_info = NULL;
249    vert_info = &llvm_vert_info;
250
251
252    if ((opt & PT_SHADE) && gshader) {
253       draw_geometry_shader_run(gshader,
254                                draw->pt.user.gs_constants,
255                                vert_info,
256                                prim_info,
257                                &gs_vert_info,
258                                &gs_prim_info);
259
260       FREE(vert_info->verts);
261       vert_info = &gs_vert_info;
262       prim_info = &gs_prim_info;
263    }
264
265    /* stream output needs to be done before clipping */
266    draw_pt_so_emit( fpme->so_emit,
267                     vert_info,
268                     prim_info );
269
270    if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) {
271       opt |= PT_PIPELINE;
272    }
273
274    /* Do we need to run the pipeline?
275     */
276    if (opt & PT_PIPELINE) {
277       pipeline( fpme,
278                 vert_info,
279                 prim_info );
280    }
281    else {
282       emit( fpme->emit,
283             vert_info,
284             prim_info );
285    }
286    FREE(vert_info->verts);
287 }
288
289
290 static void llvm_middle_end_run( struct draw_pt_middle_end *middle,
291                                  const unsigned *fetch_elts,
292                                  unsigned fetch_count,
293                                  const ushort *draw_elts,
294                                  unsigned draw_count )
295 {
296    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
297    struct draw_fetch_info fetch_info;
298    struct draw_prim_info prim_info;
299
300    fetch_info.linear = FALSE;
301    fetch_info.start = 0;
302    fetch_info.elts = fetch_elts;
303    fetch_info.count = fetch_count;
304
305    prim_info.linear = FALSE;
306    prim_info.start = 0;
307    prim_info.count = draw_count;
308    prim_info.elts = draw_elts;
309    prim_info.prim = fpme->input_prim;
310    prim_info.primitive_count = 1;
311    prim_info.primitive_lengths = &draw_count;
312
313    llvm_pipeline_generic( middle, &fetch_info, &prim_info );
314 }
315
316
317 static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle,
318                                        unsigned start,
319                                        unsigned count)
320 {
321    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
322    struct draw_fetch_info fetch_info;
323    struct draw_prim_info prim_info;
324
325    fetch_info.linear = TRUE;
326    fetch_info.start = start;
327    fetch_info.count = count;
328    fetch_info.elts = NULL;
329
330    prim_info.linear = TRUE;
331    prim_info.start = 0;
332    prim_info.count = count;
333    prim_info.elts = NULL;
334    prim_info.prim = fpme->input_prim;
335    prim_info.primitive_count = 1;
336    prim_info.primitive_lengths = &count;
337
338    llvm_pipeline_generic( middle, &fetch_info, &prim_info );
339 }
340
341
342
343 static boolean
344 llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle,
345                                  unsigned start,
346                                  unsigned count,
347                                  const ushort *draw_elts,
348                                  unsigned draw_count )
349 {
350    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
351    struct draw_fetch_info fetch_info;
352    struct draw_prim_info prim_info;
353
354    fetch_info.linear = TRUE;
355    fetch_info.start = start;
356    fetch_info.count = count;
357    fetch_info.elts = NULL;
358
359    prim_info.linear = FALSE;
360    prim_info.start = 0;
361    prim_info.count = draw_count;
362    prim_info.elts = draw_elts;
363    prim_info.prim = fpme->input_prim;
364    prim_info.primitive_count = 1;
365    prim_info.primitive_lengths = &draw_count;
366
367    llvm_pipeline_generic( middle, &fetch_info, &prim_info );
368
369    return TRUE;
370 }
371
372
373
374 static void llvm_middle_end_finish( struct draw_pt_middle_end *middle )
375 {
376    /* nothing to do */
377 }
378
379 static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
380 {
381    struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
382
383    if (fpme->fetch)
384       draw_pt_fetch_destroy( fpme->fetch );
385
386    if (fpme->emit)
387       draw_pt_emit_destroy( fpme->emit );
388
389    if (fpme->so_emit)
390       draw_pt_so_emit_destroy( fpme->so_emit );
391
392    if (fpme->post_vs)
393       draw_pt_post_vs_destroy( fpme->post_vs );
394
395    if (fpme->llvm)
396       draw_llvm_destroy( fpme->llvm );
397
398    FREE(middle);
399 }
400
401
402 struct draw_pt_middle_end *
403 draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw)
404 {
405    struct llvm_middle_end *fpme = 0;
406
407    if (!draw->engine)
408       return NULL;
409
410    fpme = CALLOC_STRUCT( llvm_middle_end );
411    if (!fpme)
412       goto fail;
413
414    fpme->base.prepare         = llvm_middle_end_prepare;
415    fpme->base.run             = llvm_middle_end_run;
416    fpme->base.run_linear      = llvm_middle_end_linear_run;
417    fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
418    fpme->base.finish          = llvm_middle_end_finish;
419    fpme->base.destroy         = llvm_middle_end_destroy;
420
421    fpme->draw = draw;
422
423    fpme->fetch = draw_pt_fetch_create( draw );
424    if (!fpme->fetch)
425       goto fail;
426
427    fpme->post_vs = draw_pt_post_vs_create( draw );
428    if (!fpme->post_vs)
429       goto fail;
430
431    fpme->emit = draw_pt_emit_create( draw );
432    if (!fpme->emit)
433       goto fail;
434
435    fpme->so_emit = draw_pt_so_emit_create( draw );
436    if (!fpme->so_emit)
437       goto fail;
438
439    fpme->llvm = draw_llvm_create(draw);
440    if (!fpme->llvm)
441       goto fail;
442
443    fpme->current_variant = NULL;
444
445    return &fpme->base;
446
447  fail:
448    if (fpme)
449       llvm_middle_end_destroy( &fpme->base );
450
451    return NULL;
452 }