OSDN Git Service

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