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