draw_pt_fetch_shade_pipeline_llvm.c revision bf2d2772a21748b6279c1fc3397ab75450aff74e
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
39struct 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 *variants;
56   struct draw_llvm_variant *current_variant;
57   int nr_variants;
58};
59
60
61static void
62llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
63                         unsigned in_prim,
64                         unsigned opt,
65                         unsigned *max_vertices )
66{
67   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
68   struct draw_context *draw = fpme->draw;
69   struct draw_vertex_shader *vs = draw->vs.vertex_shader;
70   struct draw_llvm_variant_key key;
71   struct draw_llvm_variant *variant = NULL;
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( vs->info.num_inputs,
84		       vs->info.num_outputs + 1 );
85
86   /* Scan for instanceID system value.
87    */
88   for (i = 0; i < vs->info.num_inputs; i++) {
89      if (vs->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   variant = fpme->variants;
134   while(variant) {
135      if(memcmp(&variant->key, &key, sizeof key) == 0)
136         break;
137
138      variant = variant->next;
139   }
140
141   if (!variant) {
142      variant = draw_llvm_prepare(fpme->llvm, nr);
143      variant->next = fpme->variants;
144      fpme->variants = variant;
145      ++fpme->nr_variants;
146   }
147   fpme->current_variant = variant;
148
149   /*XXX we only support one constant buffer */
150   fpme->llvm->jit_context.vs_constants =
151      draw->pt.user.vs_constants[0];
152   fpme->llvm->jit_context.gs_constants =
153      draw->pt.user.gs_constants[0];
154}
155
156
157static void pipeline(struct llvm_middle_end *llvm,
158                     const struct draw_vertex_info *vert_info,
159                     const struct draw_prim_info *prim_info)
160{
161   if (prim_info->linear)
162      draw_pipeline_run_linear( llvm->draw,
163                                vert_info,
164                                prim_info);
165   else
166      draw_pipeline_run( llvm->draw,
167                         vert_info,
168                         prim_info );
169}
170
171static void emit(struct pt_emit *emit,
172                 const struct draw_vertex_info *vert_info,
173                 const struct draw_prim_info *prim_info)
174{
175   if (prim_info->linear) {
176      draw_pt_emit_linear(emit, vert_info, prim_info);
177   }
178   else {
179      draw_pt_emit(emit, vert_info, prim_info);
180   }
181}
182
183static void
184llvm_pipeline_generic( struct draw_pt_middle_end *middle,
185                       const struct draw_fetch_info *fetch_info,
186                       const struct draw_prim_info *prim_info )
187{
188   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
189   struct draw_context *draw = fpme->draw;
190   struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
191   struct draw_prim_info gs_prim_info;
192   struct draw_vertex_info llvm_vert_info;
193   struct draw_vertex_info gs_vert_info;
194   struct draw_vertex_info *vert_info;
195   unsigned opt = fpme->opt;
196
197   llvm_vert_info.count = fetch_info->count;
198   llvm_vert_info.vertex_size = fpme->vertex_size;
199   llvm_vert_info.stride = fpme->vertex_size;
200   llvm_vert_info.verts =
201      (struct vertex_header *)MALLOC(fpme->vertex_size *
202                                     align(fetch_info->count,  4));
203   if (!llvm_vert_info.verts) {
204      assert(0);
205      return;
206   }
207
208   if (fetch_info->linear)
209      fpme->current_variant->jit_func( &fpme->llvm->jit_context,
210                                       llvm_vert_info.verts,
211                                       (const char **)draw->pt.user.vbuffer,
212                                       fetch_info->start,
213                                       fetch_info->count,
214                                       fpme->vertex_size,
215                                       draw->pt.vertex_buffer );
216   else
217      fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
218                                            llvm_vert_info.verts,
219                                            (const char **)draw->pt.user.vbuffer,
220                                            fetch_info->elts,
221                                            fetch_info->count,
222                                            fpme->vertex_size,
223                                            draw->pt.vertex_buffer);
224
225   /* Finished with fetch and vs:
226    */
227   fetch_info = NULL;
228   vert_info = &llvm_vert_info;
229
230
231   if ((opt & PT_SHADE) && gshader) {
232      draw_geometry_shader_run(gshader,
233                               draw->pt.user.gs_constants,
234                               vert_info,
235                               prim_info,
236                               &gs_vert_info,
237                               &gs_prim_info);
238
239      FREE(vert_info->verts);
240      vert_info = &gs_vert_info;
241      prim_info = &gs_prim_info;
242   }
243
244   /* stream output needs to be done before clipping */
245   draw_pt_so_emit( fpme->so_emit,
246		    vert_info,
247                    prim_info );
248
249   if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) {
250      opt |= PT_PIPELINE;
251   }
252
253   /* Do we need to run the pipeline?
254    */
255   if (opt & PT_PIPELINE) {
256      pipeline( fpme,
257                vert_info,
258                prim_info );
259   }
260   else {
261      emit( fpme->emit,
262            vert_info,
263            prim_info );
264   }
265   FREE(vert_info->verts);
266}
267
268
269static void llvm_middle_end_run( struct draw_pt_middle_end *middle,
270                                 const unsigned *fetch_elts,
271                                 unsigned fetch_count,
272                                 const ushort *draw_elts,
273                                 unsigned draw_count )
274{
275   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
276   struct draw_fetch_info fetch_info;
277   struct draw_prim_info prim_info;
278
279   fetch_info.linear = FALSE;
280   fetch_info.start = 0;
281   fetch_info.elts = fetch_elts;
282   fetch_info.count = fetch_count;
283
284   prim_info.linear = FALSE;
285   prim_info.start = 0;
286   prim_info.count = draw_count;
287   prim_info.elts = draw_elts;
288   prim_info.prim = fpme->input_prim;
289   prim_info.primitive_count = 1;
290   prim_info.primitive_lengths = &draw_count;
291
292   llvm_pipeline_generic( middle, &fetch_info, &prim_info );
293}
294
295
296static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle,
297                                       unsigned start,
298                                       unsigned count)
299{
300   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
301   struct draw_fetch_info fetch_info;
302   struct draw_prim_info prim_info;
303
304   fetch_info.linear = TRUE;
305   fetch_info.start = start;
306   fetch_info.count = count;
307   fetch_info.elts = NULL;
308
309   prim_info.linear = TRUE;
310   prim_info.start = 0;
311   prim_info.count = count;
312   prim_info.elts = NULL;
313   prim_info.prim = fpme->input_prim;
314   prim_info.primitive_count = 1;
315   prim_info.primitive_lengths = &count;
316
317   llvm_pipeline_generic( middle, &fetch_info, &prim_info );
318}
319
320
321
322static boolean
323llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle,
324                                 unsigned start,
325                                 unsigned count,
326                                 const ushort *draw_elts,
327                                 unsigned draw_count )
328{
329   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
330   struct draw_fetch_info fetch_info;
331   struct draw_prim_info prim_info;
332
333   fetch_info.linear = TRUE;
334   fetch_info.start = start;
335   fetch_info.count = count;
336   fetch_info.elts = NULL;
337
338   prim_info.linear = FALSE;
339   prim_info.start = 0;
340   prim_info.count = draw_count;
341   prim_info.elts = draw_elts;
342   prim_info.prim = fpme->input_prim;
343   prim_info.primitive_count = 1;
344   prim_info.primitive_lengths = &draw_count;
345
346   llvm_pipeline_generic( middle, &fetch_info, &prim_info );
347
348   return TRUE;
349}
350
351
352
353static void llvm_middle_end_finish( struct draw_pt_middle_end *middle )
354{
355   /* nothing to do */
356}
357
358static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
359{
360   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
361   struct draw_context *draw = fpme->draw;
362   struct draw_llvm_variant *variant = NULL;
363
364   variant = fpme->variants;
365   while(variant) {
366      struct draw_llvm_variant *next = variant->next;
367
368      if (variant->function_elts) {
369         if (variant->function_elts)
370            LLVMFreeMachineCodeForFunction(draw->engine,
371                                           variant->function_elts);
372         LLVMDeleteFunction(variant->function_elts);
373      }
374
375      if (variant->function) {
376         if (variant->function)
377            LLVMFreeMachineCodeForFunction(draw->engine,
378                                           variant->function);
379         LLVMDeleteFunction(variant->function);
380      }
381
382      FREE(variant);
383
384      variant = next;
385   }
386   if (fpme->fetch)
387      draw_pt_fetch_destroy( fpme->fetch );
388
389   if (fpme->emit)
390      draw_pt_emit_destroy( fpme->emit );
391
392   if (fpme->so_emit)
393      draw_pt_so_emit_destroy( fpme->so_emit );
394
395   if (fpme->post_vs)
396      draw_pt_post_vs_destroy( fpme->post_vs );
397
398   if (fpme->llvm)
399      draw_llvm_destroy( fpme->llvm );
400
401   FREE(middle);
402}
403
404
405struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm( struct draw_context *draw )
406{
407   struct llvm_middle_end *fpme = 0;
408
409   if (!draw->engine)
410      return NULL;
411
412   fpme = CALLOC_STRUCT( llvm_middle_end );
413   if (!fpme)
414      goto fail;
415
416   fpme->base.prepare         = llvm_middle_end_prepare;
417   fpme->base.run             = llvm_middle_end_run;
418   fpme->base.run_linear      = llvm_middle_end_linear_run;
419   fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
420   fpme->base.finish          = llvm_middle_end_finish;
421   fpme->base.destroy         = llvm_middle_end_destroy;
422
423   fpme->draw = draw;
424
425   fpme->fetch = draw_pt_fetch_create( draw );
426   if (!fpme->fetch)
427      goto fail;
428
429   fpme->post_vs = draw_pt_post_vs_create( draw );
430   if (!fpme->post_vs)
431      goto fail;
432
433   fpme->emit = draw_pt_emit_create( draw );
434   if (!fpme->emit)
435      goto fail;
436
437   fpme->so_emit = draw_pt_so_emit_create( draw );
438   if (!fpme->so_emit)
439      goto fail;
440
441   fpme->llvm = draw_llvm_create(draw);
442   if (!fpme->llvm)
443      goto fail;
444
445   fpme->variants = NULL;
446   fpme->current_variant = NULL;
447   fpme->nr_variants = 0;
448
449   return &fpme->base;
450
451 fail:
452   if (fpme)
453      llvm_middle_end_destroy( &fpme->base );
454
455   return NULL;
456}
457