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