draw: rearrange code in llvm_middle_end_prepare()
[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_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 #include "gallivm/lp_bld_init.h"
38
39
40 struct llvm_middle_end {
41 struct draw_pt_middle_end base;
42 struct draw_context *draw;
43
44 struct pt_emit *emit;
45 struct pt_so_emit *so_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 input_prim;
53 unsigned opt;
54
55 struct draw_llvm *llvm;
56 struct draw_llvm_variant *current_variant;
57 };
58
59
60 static void
61 llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
62 unsigned in_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_geometry_shader *gs = draw->gs.geometry_shader;
70 const unsigned out_prim = gs ? gs->output_primitive : in_prim;
71
72 /* Add one to num_outputs because the pipeline occasionally tags on
73 * an additional texcoord, eg for AA lines.
74 */
75 const unsigned nr = MAX2( vs->info.num_inputs,
76 vs->info.num_outputs + 1 );
77
78 fpme->input_prim = in_prim;
79 fpme->opt = opt;
80
81 /* Always leave room for the vertex header whether we need it or
82 * not. It's hard to get rid of it in particular because of the
83 * viewport code in draw_pt_post_vs.c.
84 */
85 fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
86
87
88 /* XXX: it's not really gl rasterization rules we care about here,
89 * but gl vs dx9 clip spaces.
90 */
91 draw_pt_post_vs_prepare( fpme->post_vs,
92 draw->clip_xy,
93 draw->clip_z,
94 draw->clip_user,
95 draw->guard_band_xy,
96 draw->identity_viewport,
97 (boolean)draw->rasterizer->gl_rasterization_rules,
98 (draw->vs.edgeflag_output ? TRUE : FALSE) );
99
100 draw_pt_so_emit_prepare( fpme->so_emit );
101
102 if (!(opt & PT_PIPELINE)) {
103 draw_pt_emit_prepare( fpme->emit,
104 out_prim,
105 max_vertices );
106
107 *max_vertices = MAX2( *max_vertices, 4096 );
108 }
109 else {
110 /* limit max fetches by limiting max_vertices */
111 *max_vertices = 4096;
112 }
113
114 /* return even number */
115 *max_vertices = *max_vertices & ~1;
116
117 /* Find/create the vertex shader variant */
118 {
119 struct draw_llvm_variant_key *key;
120 struct draw_llvm_variant *variant = NULL;
121 struct draw_llvm_variant_list_item *li;
122 struct llvm_vertex_shader *shader = llvm_vertex_shader(vs);
123 char store[DRAW_LLVM_MAX_VARIANT_KEY_SIZE];
124 unsigned i;
125
126 key = draw_llvm_make_variant_key(fpme->llvm, store);
127
128 /* Search shader's list of variants for the key */
129 li = first_elem(&shader->variants);
130 while (!at_end(&shader->variants, li)) {
131 if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
132 variant = li->base;
133 break;
134 }
135 li = next_elem(li);
136 }
137
138 if (variant) {
139 /* found the variant, move to head of global list (for LRU) */
140 move_to_head(&fpme->llvm->vs_variants_list,
141 &variant->list_item_global);
142 }
143 else {
144 /* Need to create new variant */
145
146 /* First check if we've created too many variants. If so, free
147 * 25% of the LRU to avoid using too much memory.
148 */
149 if (fpme->llvm->nr_variants >= DRAW_MAX_SHADER_VARIANTS) {
150 /*
151 * XXX: should we flush here ?
152 */
153 for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 4; i++) {
154 struct draw_llvm_variant_list_item *item;
155 if (is_empty_list(&fpme->llvm->vs_variants_list)) {
156 break;
157 }
158 item = last_elem(&fpme->llvm->vs_variants_list);
159 assert(item);
160 assert(item->base);
161 draw_llvm_destroy_variant(item->base);
162 }
163 }
164
165 variant = draw_llvm_create_variant(fpme->llvm, nr, key);
166
167 if (variant) {
168 insert_at_head(&shader->variants, &variant->list_item_local);
169 insert_at_head(&fpme->llvm->vs_variants_list,
170 &variant->list_item_global);
171 fpme->llvm->nr_variants++;
172 shader->variants_cached++;
173 }
174 }
175
176 fpme->current_variant = variant;
177 }
178
179 /* Bind the VS and GS input constants, clip planes and viewport */
180 {
181 unsigned i;
182
183 for (i = 0; i < Elements(fpme->llvm->jit_context.vs_constants); ++i) {
184 fpme->llvm->jit_context.vs_constants[i] =
185 draw->pt.user.vs_constants[i];
186 }
187 for (i = 0; i < Elements(fpme->llvm->jit_context.gs_constants); ++i) {
188 fpme->llvm->jit_context.gs_constants[i] =
189 draw->pt.user.gs_constants[i];
190 }
191 fpme->llvm->jit_context.planes =
192 (float (*) [DRAW_TOTAL_CLIP_PLANES][4]) draw->pt.user.planes[0];
193 fpme->llvm->jit_context.viewport =
194 (float *) draw->viewport.scale;
195 }
196 }
197
198
199 static void pipeline(struct llvm_middle_end *llvm,
200 const struct draw_vertex_info *vert_info,
201 const struct draw_prim_info *prim_info)
202 {
203 if (prim_info->linear)
204 draw_pipeline_run_linear( llvm->draw,
205 vert_info,
206 prim_info);
207 else
208 draw_pipeline_run( llvm->draw,
209 vert_info,
210 prim_info );
211 }
212
213 static void emit(struct pt_emit *emit,
214 const struct draw_vertex_info *vert_info,
215 const struct draw_prim_info *prim_info)
216 {
217 if (prim_info->linear) {
218 draw_pt_emit_linear(emit, vert_info, prim_info);
219 }
220 else {
221 draw_pt_emit(emit, vert_info, prim_info);
222 }
223 }
224
225 static void
226 llvm_pipeline_generic( struct draw_pt_middle_end *middle,
227 const struct draw_fetch_info *fetch_info,
228 const struct draw_prim_info *prim_info )
229 {
230 struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
231 struct draw_context *draw = fpme->draw;
232 struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
233 struct draw_prim_info gs_prim_info;
234 struct draw_vertex_info llvm_vert_info;
235 struct draw_vertex_info gs_vert_info;
236 struct draw_vertex_info *vert_info;
237 unsigned opt = fpme->opt;
238 unsigned clipped = 0;
239
240 llvm_vert_info.count = fetch_info->count;
241 llvm_vert_info.vertex_size = fpme->vertex_size;
242 llvm_vert_info.stride = fpme->vertex_size;
243 llvm_vert_info.verts =
244 (struct vertex_header *)MALLOC(fpme->vertex_size *
245 align(fetch_info->count, lp_native_vector_width / 32));
246 if (!llvm_vert_info.verts) {
247 assert(0);
248 return;
249 }
250
251 if (fetch_info->linear)
252 clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context,
253 llvm_vert_info.verts,
254 (const char **)draw->pt.user.vbuffer,
255 fetch_info->start,
256 fetch_info->count,
257 fpme->vertex_size,
258 draw->pt.vertex_buffer,
259 draw->instance_id);
260 else
261 clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
262 llvm_vert_info.verts,
263 (const char **)draw->pt.user.vbuffer,
264 fetch_info->elts,
265 fetch_info->count,
266 fpme->vertex_size,
267 draw->pt.vertex_buffer,
268 draw->instance_id);
269
270 /* Finished with fetch and vs:
271 */
272 fetch_info = NULL;
273 vert_info = &llvm_vert_info;
274
275
276 if ((opt & PT_SHADE) && gshader) {
277 draw_geometry_shader_run(gshader,
278 draw->pt.user.gs_constants,
279 draw->pt.user.gs_constants_size,
280 vert_info,
281 prim_info,
282 &gs_vert_info,
283 &gs_prim_info);
284
285 FREE(vert_info->verts);
286 vert_info = &gs_vert_info;
287 prim_info = &gs_prim_info;
288
289 clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info );
290
291 }
292
293 /* stream output needs to be done before clipping */
294 draw_pt_so_emit( fpme->so_emit,
295 vert_info,
296 prim_info );
297
298 if (clipped) {
299 opt |= PT_PIPELINE;
300 }
301
302 /* Do we need to run the pipeline? Now will come here if clipped
303 */
304 if (opt & PT_PIPELINE) {
305 pipeline( fpme,
306 vert_info,
307 prim_info );
308 }
309 else {
310 emit( fpme->emit,
311 vert_info,
312 prim_info );
313 }
314 FREE(vert_info->verts);
315 }
316
317
318 static void llvm_middle_end_run( struct draw_pt_middle_end *middle,
319 const unsigned *fetch_elts,
320 unsigned fetch_count,
321 const ushort *draw_elts,
322 unsigned draw_count,
323 unsigned prim_flags )
324 {
325 struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
326 struct draw_fetch_info fetch_info;
327 struct draw_prim_info prim_info;
328
329 fetch_info.linear = FALSE;
330 fetch_info.start = 0;
331 fetch_info.elts = fetch_elts;
332 fetch_info.count = fetch_count;
333
334 prim_info.linear = FALSE;
335 prim_info.start = 0;
336 prim_info.count = draw_count;
337 prim_info.elts = draw_elts;
338 prim_info.prim = fpme->input_prim;
339 prim_info.flags = prim_flags;
340 prim_info.primitive_count = 1;
341 prim_info.primitive_lengths = &draw_count;
342
343 llvm_pipeline_generic( middle, &fetch_info, &prim_info );
344 }
345
346
347 static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle,
348 unsigned start,
349 unsigned count,
350 unsigned prim_flags)
351 {
352 struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
353 struct draw_fetch_info fetch_info;
354 struct draw_prim_info prim_info;
355
356 fetch_info.linear = TRUE;
357 fetch_info.start = start;
358 fetch_info.count = count;
359 fetch_info.elts = NULL;
360
361 prim_info.linear = TRUE;
362 prim_info.start = 0;
363 prim_info.count = count;
364 prim_info.elts = NULL;
365 prim_info.prim = fpme->input_prim;
366 prim_info.flags = prim_flags;
367 prim_info.primitive_count = 1;
368 prim_info.primitive_lengths = &count;
369
370 llvm_pipeline_generic( middle, &fetch_info, &prim_info );
371 }
372
373
374
375 static boolean
376 llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle,
377 unsigned start,
378 unsigned count,
379 const ushort *draw_elts,
380 unsigned draw_count,
381 unsigned prim_flags )
382 {
383 struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
384 struct draw_fetch_info fetch_info;
385 struct draw_prim_info prim_info;
386
387 fetch_info.linear = TRUE;
388 fetch_info.start = start;
389 fetch_info.count = count;
390 fetch_info.elts = NULL;
391
392 prim_info.linear = FALSE;
393 prim_info.start = 0;
394 prim_info.count = draw_count;
395 prim_info.elts = draw_elts;
396 prim_info.prim = fpme->input_prim;
397 prim_info.flags = prim_flags;
398 prim_info.primitive_count = 1;
399 prim_info.primitive_lengths = &draw_count;
400
401 llvm_pipeline_generic( middle, &fetch_info, &prim_info );
402
403 return TRUE;
404 }
405
406
407
408 static void llvm_middle_end_finish( struct draw_pt_middle_end *middle )
409 {
410 /* nothing to do */
411 }
412
413 static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
414 {
415 struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
416
417 if (fpme->fetch)
418 draw_pt_fetch_destroy( fpme->fetch );
419
420 if (fpme->emit)
421 draw_pt_emit_destroy( fpme->emit );
422
423 if (fpme->so_emit)
424 draw_pt_so_emit_destroy( fpme->so_emit );
425
426 if (fpme->post_vs)
427 draw_pt_post_vs_destroy( fpme->post_vs );
428
429 FREE(middle);
430 }
431
432
433 struct draw_pt_middle_end *
434 draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw)
435 {
436 struct llvm_middle_end *fpme = 0;
437
438 if (!draw->llvm)
439 return NULL;
440
441 fpme = CALLOC_STRUCT( llvm_middle_end );
442 if (!fpme)
443 goto fail;
444
445 fpme->base.prepare = llvm_middle_end_prepare;
446 fpme->base.run = llvm_middle_end_run;
447 fpme->base.run_linear = llvm_middle_end_linear_run;
448 fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
449 fpme->base.finish = llvm_middle_end_finish;
450 fpme->base.destroy = llvm_middle_end_destroy;
451
452 fpme->draw = draw;
453
454 fpme->fetch = draw_pt_fetch_create( draw );
455 if (!fpme->fetch)
456 goto fail;
457
458 fpme->post_vs = draw_pt_post_vs_create( draw );
459 if (!fpme->post_vs)
460 goto fail;
461
462 fpme->emit = draw_pt_emit_create( draw );
463 if (!fpme->emit)
464 goto fail;
465
466 fpme->so_emit = draw_pt_so_emit_create( draw );
467 if (!fpme->so_emit)
468 goto fail;
469
470 fpme->llvm = draw->llvm;
471 if (!fpme->llvm)
472 goto fail;
473
474 fpme->current_variant = NULL;
475
476 return &fpme->base;
477
478 fail:
479 if (fpme)
480 llvm_middle_end_destroy( &fpme->base );
481
482 return NULL;
483 }