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