OSDN Git Service

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