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