1/************************************************************************** 2 * 3 * Copyright 2009 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 "draw_gs.h" 29 30#include "draw_private.h" 31#include "draw_context.h" 32 33#include "tgsi/tgsi_parse.h" 34#include "tgsi/tgsi_exec.h" 35 36#include "pipe/p_shader_tokens.h" 37 38#include "util/u_math.h" 39#include "util/u_memory.h" 40#include "util/u_prim.h" 41 42/* fixme: move it from here */ 43#define MAX_PRIMITIVES 64 44 45boolean 46draw_gs_init( struct draw_context *draw ) 47{ 48 draw->gs.tgsi.machine = tgsi_exec_machine_create(); 49 if (!draw->gs.tgsi.machine) 50 return FALSE; 51 52 draw->gs.tgsi.machine->Primitives = align_malloc( 53 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16); 54 if (!draw->gs.tgsi.machine->Primitives) 55 return FALSE; 56 memset(draw->gs.tgsi.machine->Primitives, 0, 57 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector)); 58 59 return TRUE; 60} 61 62void draw_gs_destroy( struct draw_context *draw ) 63{ 64 if (!draw->gs.tgsi.machine) 65 return; 66 67 align_free(draw->gs.tgsi.machine->Primitives); 68 69 tgsi_exec_machine_destroy(draw->gs.tgsi.machine); 70} 71 72void 73draw_gs_set_constants(struct draw_context *draw, 74 unsigned slot, 75 const void *constants, 76 unsigned size) 77{ 78 /* noop. added here for symmetry with the VS 79 * code and in case we'll ever want to allign 80 * the constants, e.g. when we'll change to a 81 * different interpreter */ 82} 83 84 85struct draw_geometry_shader * 86draw_create_geometry_shader(struct draw_context *draw, 87 const struct pipe_shader_state *state) 88{ 89 struct draw_geometry_shader *gs; 90 int i; 91 92 gs = CALLOC_STRUCT(draw_geometry_shader); 93 94 if (!gs) 95 return NULL; 96 97 gs->draw = draw; 98 gs->state = *state; 99 gs->state.tokens = tgsi_dup_tokens(state->tokens); 100 if (!gs->state.tokens) { 101 FREE(gs); 102 return NULL; 103 } 104 105 tgsi_scan_shader(state->tokens, &gs->info); 106 107 /* setup the defaults */ 108 gs->input_primitive = PIPE_PRIM_TRIANGLES; 109 gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP; 110 gs->max_output_vertices = 32; 111 112 for (i = 0; i < gs->info.num_properties; ++i) { 113 if (gs->info.properties[i].name == 114 TGSI_PROPERTY_GS_INPUT_PRIM) 115 gs->input_primitive = gs->info.properties[i].data[0]; 116 else if (gs->info.properties[i].name == 117 TGSI_PROPERTY_GS_OUTPUT_PRIM) 118 gs->output_primitive = gs->info.properties[i].data[0]; 119 else if (gs->info.properties[i].name == 120 TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) 121 gs->max_output_vertices = gs->info.properties[i].data[0]; 122 } 123 124 gs->machine = draw->gs.tgsi.machine; 125 126 if (gs) 127 { 128 uint i; 129 for (i = 0; i < gs->info.num_outputs; i++) { 130 if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION && 131 gs->info.output_semantic_index[i] == 0) 132 gs->position_output = i; 133 } 134 } 135 136 return gs; 137} 138 139void draw_bind_geometry_shader(struct draw_context *draw, 140 struct draw_geometry_shader *dgs) 141{ 142 draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE); 143 144 if (dgs) { 145 draw->gs.geometry_shader = dgs; 146 draw->gs.num_gs_outputs = dgs->info.num_outputs; 147 draw->gs.position_output = dgs->position_output; 148 draw_geometry_shader_prepare(dgs, draw); 149 } 150 else { 151 draw->gs.geometry_shader = NULL; 152 draw->gs.num_gs_outputs = 0; 153 } 154} 155 156void draw_delete_geometry_shader(struct draw_context *draw, 157 struct draw_geometry_shader *dgs) 158{ 159 FREE(dgs); 160} 161 162/*#define DEBUG_OUTPUTS 1*/ 163static INLINE void 164draw_geometry_fetch_outputs(struct draw_geometry_shader *shader, 165 int num_primitives, 166 float (**p_output)[4]) 167{ 168 struct tgsi_exec_machine *machine = shader->machine; 169 unsigned prim_idx, j, slot; 170 float (*output)[4]; 171 172 output = *p_output; 173 174 /* Unswizzle all output results. 175 */ 176 177 for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) { 178 unsigned num_verts_per_prim = machine->Primitives[prim_idx]; 179 shader->primitive_lengths[prim_idx + shader->emitted_primitives] = 180 machine->Primitives[prim_idx]; 181 shader->emitted_vertices += num_verts_per_prim; 182 for (j = 0; j < num_verts_per_prim; j++) { 183 int idx = (prim_idx * num_verts_per_prim + j) * 184 shader->info.num_outputs; 185#ifdef DEBUG_OUTPUTS 186 debug_printf("%d) Output vert:\n", idx / shader->info.num_outputs); 187#endif 188 for (slot = 0; slot < shader->info.num_outputs; slot++) { 189 output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[0]; 190 output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[0]; 191 output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[0]; 192 output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[0]; 193#ifdef DEBUG_OUTPUTS 194 debug_printf("\t%d: %f %f %f %f\n", slot, 195 output[slot][0], 196 output[slot][1], 197 output[slot][2], 198 output[slot][3]); 199#endif 200 debug_assert(!util_is_inf_or_nan(output[slot][0])); 201 } 202 output = (float (*)[4])((char *)output + shader->vertex_size); 203 } 204 } 205 *p_output = output; 206 shader->emitted_primitives += num_primitives; 207} 208 209/*#define DEBUG_INPUTS 1*/ 210static void draw_fetch_gs_input(struct draw_geometry_shader *shader, 211 unsigned *indices, 212 unsigned num_vertices, 213 unsigned prim_idx) 214{ 215 struct tgsi_exec_machine *machine = shader->machine; 216 unsigned slot, vs_slot, i; 217 unsigned input_vertex_stride = shader->input_vertex_stride; 218 const float (*input_ptr)[4]; 219 220 input_ptr = shader->input; 221 222 for (i = 0; i < num_vertices; ++i) { 223 const float (*input)[4]; 224#if DEBUG_INPUTS 225 debug_printf("%d) vertex index = %d (prim idx = %d)\n", 226 i, indices[i], prim_idx); 227#endif 228 input = (const float (*)[4])( 229 (const char *)input_ptr + (indices[i] * input_vertex_stride)); 230 for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) { 231 unsigned idx = i * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot; 232 if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) { 233 machine->Inputs[idx].xyzw[0].f[prim_idx] = 234 (float)shader->in_prim_idx; 235 machine->Inputs[idx].xyzw[1].f[prim_idx] = 236 (float)shader->in_prim_idx; 237 machine->Inputs[idx].xyzw[2].f[prim_idx] = 238 (float)shader->in_prim_idx; 239 machine->Inputs[idx].xyzw[3].f[prim_idx] = 240 (float)shader->in_prim_idx; 241 } else { 242#if DEBUG_INPUTS 243 debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n", 244 slot, vs_slot, idx); 245#endif 246#if 1 247 assert(!util_is_inf_or_nan(input[vs_slot][0])); 248 assert(!util_is_inf_or_nan(input[vs_slot][1])); 249 assert(!util_is_inf_or_nan(input[vs_slot][2])); 250 assert(!util_is_inf_or_nan(input[vs_slot][3])); 251#endif 252 machine->Inputs[idx].xyzw[0].f[prim_idx] = input[vs_slot][0]; 253 machine->Inputs[idx].xyzw[1].f[prim_idx] = input[vs_slot][1]; 254 machine->Inputs[idx].xyzw[2].f[prim_idx] = input[vs_slot][2]; 255 machine->Inputs[idx].xyzw[3].f[prim_idx] = input[vs_slot][3]; 256#if DEBUG_INPUTS 257 debug_printf("\t\t%f %f %f %f\n", 258 machine->Inputs[idx].xyzw[0].f[prim_idx], 259 machine->Inputs[idx].xyzw[1].f[prim_idx], 260 machine->Inputs[idx].xyzw[2].f[prim_idx], 261 machine->Inputs[idx].xyzw[3].f[prim_idx]); 262#endif 263 ++vs_slot; 264 } 265 } 266 } 267} 268 269static void gs_flush(struct draw_geometry_shader *shader, 270 unsigned input_primitives) 271{ 272 unsigned out_prim_count; 273 struct tgsi_exec_machine *machine = shader->machine; 274 275 debug_assert(input_primitives > 0 && 276 input_primitives < 4); 277 278 tgsi_set_exec_mask(machine, 279 1, 280 input_primitives > 1, 281 input_primitives > 2, 282 input_primitives > 3); 283 284 /* run interpreter */ 285 tgsi_exec_machine_run(machine); 286 287 out_prim_count = 288 machine->Temps[TGSI_EXEC_TEMP_PRIMITIVE_I].xyzw[TGSI_EXEC_TEMP_PRIMITIVE_C].u[0]; 289 290#if 0 291 debug_printf("PRIM emitted prims = %d (verts=%d), cur prim count = %d\n", 292 shader->emitted_primitives, shader->emitted_vertices, 293 out_prim_count); 294#endif 295 draw_geometry_fetch_outputs(shader, out_prim_count, 296 &shader->tmp_output); 297} 298 299static void gs_point(struct draw_geometry_shader *shader, 300 int idx) 301{ 302 unsigned indices[1]; 303 304 indices[0] = idx; 305 306 draw_fetch_gs_input(shader, indices, 1, 0); 307 ++shader->in_prim_idx; 308 309 gs_flush(shader, 1); 310} 311 312static void gs_line(struct draw_geometry_shader *shader, 313 int i0, int i1) 314{ 315 unsigned indices[2]; 316 317 indices[0] = i0; 318 indices[1] = i1; 319 320 draw_fetch_gs_input(shader, indices, 2, 0); 321 ++shader->in_prim_idx; 322 323 gs_flush(shader, 1); 324} 325 326static void gs_line_adj(struct draw_geometry_shader *shader, 327 int i0, int i1, int i2, int i3) 328{ 329 unsigned indices[4]; 330 331 indices[0] = i0; 332 indices[1] = i1; 333 indices[2] = i2; 334 indices[3] = i3; 335 336 draw_fetch_gs_input(shader, indices, 4, 0); 337 ++shader->in_prim_idx; 338 339 gs_flush(shader, 1); 340} 341 342static void gs_tri(struct draw_geometry_shader *shader, 343 int i0, int i1, int i2) 344{ 345 unsigned indices[3]; 346 347 indices[0] = i0; 348 indices[1] = i1; 349 indices[2] = i2; 350 351 draw_fetch_gs_input(shader, indices, 3, 0); 352 ++shader->in_prim_idx; 353 354 gs_flush(shader, 1); 355} 356 357static void gs_tri_adj(struct draw_geometry_shader *shader, 358 int i0, int i1, int i2, 359 int i3, int i4, int i5) 360{ 361 unsigned indices[6]; 362 363 indices[0] = i0; 364 indices[1] = i1; 365 indices[2] = i2; 366 indices[3] = i3; 367 indices[4] = i4; 368 indices[5] = i5; 369 370 draw_fetch_gs_input(shader, indices, 6, 0); 371 ++shader->in_prim_idx; 372 373 gs_flush(shader, 1); 374} 375 376#define FUNC gs_run 377#define GET_ELT(idx) (idx) 378#include "draw_gs_tmp.h" 379 380 381#define FUNC gs_run_elts 382#define LOCAL_VARS const ushort *elts = input_prims->elts; 383#define GET_ELT(idx) (elts[idx]) 384#include "draw_gs_tmp.h" 385 386 387/** 388 * Execute geometry shader using TGSI interpreter. 389 */ 390int draw_geometry_shader_run(struct draw_geometry_shader *shader, 391 const void *constants[PIPE_MAX_CONSTANT_BUFFERS], 392 const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS], 393 const struct draw_vertex_info *input_verts, 394 const struct draw_prim_info *input_prim, 395 struct draw_vertex_info *output_verts, 396 struct draw_prim_info *output_prims ) 397{ 398 const float (*input)[4] = (const float (*)[4])input_verts->verts->data; 399 unsigned input_stride = input_verts->vertex_size; 400 unsigned vertex_size = input_verts->vertex_size; 401 struct tgsi_exec_machine *machine = shader->machine; 402 unsigned num_input_verts = input_prim->linear ? 403 input_verts->count : 404 input_prim->count; 405 unsigned num_in_primitives = 406 MAX2(u_gs_prims_for_vertices(input_prim->prim, num_input_verts), 407 u_gs_prims_for_vertices(shader->input_primitive, num_input_verts)); 408 unsigned max_out_prims = u_gs_prims_for_vertices(shader->output_primitive, 409 shader->max_output_vertices) 410 * num_in_primitives; 411 412 output_verts->vertex_size = input_verts->vertex_size; 413 output_verts->stride = input_verts->vertex_size; 414 output_verts->verts = 415 (struct vertex_header *)MALLOC(input_verts->vertex_size * 416 num_in_primitives * 417 shader->max_output_vertices); 418 419 420#if 0 421 debug_printf("%s count = %d (in prims # = %d)\n", 422 __FUNCTION__, num_input_verts, num_in_primitives); 423 debug_printf("\tlinear = %d, prim_info->count = %d\n", 424 input_prim->linear, input_prim->count); 425 debug_printf("\tprimt pipe = %d, shader in = %d, shader out = %d, max out = %d\n", 426 input_prim->prim, shader->input_primitive, 427 shader->output_primitive, 428 shader->max_output_vertices); 429#endif 430 431 shader->emitted_vertices = 0; 432 shader->emitted_primitives = 0; 433 shader->vertex_size = vertex_size; 434 shader->tmp_output = (float (*)[4])output_verts->verts->data; 435 shader->in_prim_idx = 0; 436 shader->input_vertex_stride = input_stride; 437 shader->input = input; 438 if (shader->primitive_lengths) { 439 FREE(shader->primitive_lengths); 440 } 441 shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned)); 442 443 tgsi_exec_set_constant_buffers(machine, PIPE_MAX_CONSTANT_BUFFERS, 444 constants, constants_size); 445 446 if (input_prim->linear) 447 gs_run(shader, input_prim, input_verts, 448 output_prims, output_verts); 449 else 450 gs_run_elts(shader, input_prim, input_verts, 451 output_prims, output_verts); 452 453 /* Update prim_info: 454 */ 455 output_prims->linear = TRUE; 456 output_prims->elts = NULL; 457 output_prims->start = 0; 458 output_prims->count = shader->emitted_vertices; 459 output_prims->prim = shader->output_primitive; 460 output_prims->flags = 0x0; 461 output_prims->primitive_lengths = shader->primitive_lengths; 462 output_prims->primitive_count = shader->emitted_primitives; 463 output_verts->count = shader->emitted_vertices; 464 465#if 0 466 debug_printf("GS finished, prims = %d, verts = %d\n", 467 output_prims->primitive_count, 468 output_verts->count); 469#endif 470 471 return shader->emitted_vertices; 472} 473 474void draw_geometry_shader_delete(struct draw_geometry_shader *shader) 475{ 476 FREE((void*) shader->state.tokens); 477 FREE(shader); 478} 479 480void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, 481 struct draw_context *draw) 482{ 483 if (shader && shader->machine->Tokens != shader->state.tokens) { 484 tgsi_exec_machine_bind_shader(shader->machine, 485 shader->state.tokens, 486 draw->gs.tgsi.num_samplers, 487 draw->gs.tgsi.samplers); 488 } 489} 490