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