draw_gs.c revision b85a361ccbac956d2842251395c048a4b3f4c440
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#define MAX_PRIM_VERTICES 6 43/* fixme: move it from here */ 44#define MAX_PRIMITIVES 64 45 46boolean 47draw_gs_init( struct draw_context *draw ) 48{ 49 draw->gs.machine = tgsi_exec_machine_create(); 50 if (!draw->gs.machine) 51 return FALSE; 52 53 draw->gs.machine->Primitives = align_malloc( 54 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16); 55 if (!draw->gs.machine->Primitives) 56 return FALSE; 57 memset(draw->gs.machine->Primitives, 0, 58 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector)); 59 60 return TRUE; 61} 62 63void draw_gs_destroy( struct draw_context *draw ) 64{ 65 if (!draw->gs.machine) 66 return; 67 68 align_free(draw->gs.machine->Primitives); 69 70 tgsi_exec_machine_destroy(draw->gs.machine); 71} 72 73void 74draw_gs_set_constants(struct draw_context *draw, 75 unsigned slot, 76 const void *constants, 77 unsigned size) 78{ 79} 80 81 82struct draw_geometry_shader * 83draw_create_geometry_shader(struct draw_context *draw, 84 const struct pipe_shader_state *state) 85{ 86 struct draw_geometry_shader *gs; 87 int i; 88 89 gs = CALLOC_STRUCT(draw_geometry_shader); 90 91 if (!gs) 92 return NULL; 93 94 gs->draw = draw; 95 gs->state = *state; 96 gs->state.tokens = tgsi_dup_tokens(state->tokens); 97 if (!gs->state.tokens) { 98 FREE(gs); 99 return NULL; 100 } 101 102 tgsi_scan_shader(state->tokens, &gs->info); 103 104 /* setup the defaults */ 105 gs->input_primitive = PIPE_PRIM_TRIANGLES; 106 gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP; 107 gs->max_output_vertices = 32; 108 109 for (i = 0; i < gs->info.num_properties; ++i) { 110 if (gs->info.properties[i].name == 111 TGSI_PROPERTY_GS_INPUT_PRIM) 112 gs->input_primitive = gs->info.properties[i].data[0]; 113 else if (gs->info.properties[i].name == 114 TGSI_PROPERTY_GS_OUTPUT_PRIM) 115 gs->output_primitive = gs->info.properties[i].data[0]; 116 else if (gs->info.properties[i].name == 117 TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) 118 gs->max_output_vertices = gs->info.properties[i].data[0]; 119 } 120 121 gs->machine = draw->gs.machine; 122 123 if (gs) 124 { 125 uint i; 126 for (i = 0; i < gs->info.num_outputs; i++) { 127 if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION && 128 gs->info.output_semantic_index[i] == 0) 129 gs->position_output = i; 130 } 131 } 132 133 return gs; 134} 135 136void draw_bind_geometry_shader(struct draw_context *draw, 137 struct draw_geometry_shader *dgs) 138{ 139 draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE); 140 141 if (dgs) { 142 draw->gs.geometry_shader = dgs; 143 draw->gs.num_gs_outputs = dgs->info.num_outputs; 144 draw->gs.position_output = dgs->position_output; 145 draw_geometry_shader_prepare(dgs, draw); 146 } 147 else { 148 draw->gs.geometry_shader = NULL; 149 draw->gs.num_gs_outputs = 0; 150 } 151} 152 153void draw_delete_geometry_shader(struct draw_context *draw, 154 struct draw_geometry_shader *dgs) 155{ 156 FREE(dgs); 157} 158 159/*#define DEBUG_OUTPUTS 1*/ 160static INLINE void 161draw_geometry_fetch_outputs(struct draw_geometry_shader *shader, 162 int num_primitives, 163 float (**p_output)[4]) 164{ 165 struct tgsi_exec_machine *machine = shader->machine; 166 unsigned prim_idx, j, slot; 167 float (*output)[4]; 168 169 output = *p_output; 170 171 /* Unswizzle all output results. 172 */ 173 174 shader->emitted_primitives += num_primitives; 175 for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) { 176 unsigned num_verts_per_prim = machine->Primitives[prim_idx]; 177 shader->emitted_vertices += num_verts_per_prim; 178 for (j = 0; j < num_verts_per_prim; j++) { 179 int idx = (prim_idx * num_verts_per_prim + j) * 180 shader->info.num_outputs; 181#ifdef DEBUG_OUTPUTS 182 debug_printf("%d) Output vert:\n", idx / shader->info.num_outputs); 183#endif 184 for (slot = 0; slot < shader->info.num_outputs; slot++) { 185 output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[0]; 186 output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[0]; 187 output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[0]; 188 output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[0]; 189#ifdef DEBUG_OUTPUTS 190 debug_printf("\t%d: %f %f %f %f\n", slot, 191 output[slot][0], 192 output[slot][1], 193 output[slot][2], 194 output[slot][3]); 195#endif 196 debug_assert(!util_is_inf_or_nan(output[slot][0])); 197 } 198 output = (float (*)[4])((char *)output + shader->vertex_size); 199 } 200 } 201 *p_output = output; 202} 203 204 205static void draw_fetch_gs_input(struct draw_geometry_shader *shader, 206 unsigned *indices, 207 unsigned num_vertices, 208 unsigned prim_idx) 209{ 210 struct tgsi_exec_machine *machine = shader->machine; 211 unsigned slot, vs_slot, i; 212 unsigned input_vertex_stride = shader->input_vertex_stride; 213 const float (*input_ptr)[4]; 214 215 input_ptr = shader->input; 216 217 for (i = 0; i < num_vertices; ++i) { 218 const float (*input)[4]; 219 /*debug_printf("%d) vertex index = %d (prim idx = %d)\n", i, indices[i], prim_idx);*/ 220 input = (const float (*)[4])( 221 (const char *)input_ptr + (indices[i] * input_vertex_stride)); 222 for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) { 223 unsigned idx = i * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot; 224 if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) { 225 machine->Inputs[idx].xyzw[0].f[prim_idx] = (float)shader->in_prim_idx; 226 machine->Inputs[idx].xyzw[1].f[prim_idx] = (float)shader->in_prim_idx; 227 machine->Inputs[idx].xyzw[2].f[prim_idx] = (float)shader->in_prim_idx; 228 machine->Inputs[idx].xyzw[3].f[prim_idx] = (float)shader->in_prim_idx; 229 } else { 230 /*debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n", 231 slot, vs_slot, idx);*/ 232#if 1 233 assert(!util_is_inf_or_nan(input[vs_slot][0])); 234 assert(!util_is_inf_or_nan(input[vs_slot][1])); 235 assert(!util_is_inf_or_nan(input[vs_slot][2])); 236 assert(!util_is_inf_or_nan(input[vs_slot][3])); 237#endif 238 machine->Inputs[idx].xyzw[0].f[prim_idx] = input[vs_slot][0]; 239 machine->Inputs[idx].xyzw[1].f[prim_idx] = input[vs_slot][1]; 240 machine->Inputs[idx].xyzw[2].f[prim_idx] = input[vs_slot][2]; 241 machine->Inputs[idx].xyzw[3].f[prim_idx] = input[vs_slot][3]; 242#if 0 243 debug_printf("\t\t%f %f %f %f\n", 244 machine->Inputs[idx].xyzw[0].f[prim_idx], 245 machine->Inputs[idx].xyzw[1].f[prim_idx], 246 machine->Inputs[idx].xyzw[2].f[prim_idx], 247 machine->Inputs[idx].xyzw[3].f[prim_idx]); 248#endif 249 ++vs_slot; 250 } 251 } 252 } 253} 254 255 256static void gs_flush(struct draw_geometry_shader *shader, 257 unsigned input_primitives) 258{ 259 unsigned out_prim_count; 260 struct tgsi_exec_machine *machine = shader->machine; 261 262 debug_assert(input_primitives > 0 && 263 input_primitives < 4); 264 265 tgsi_set_exec_mask(machine, 266 1, 267 input_primitives > 1, 268 input_primitives > 2, 269 input_primitives > 3); 270 271 /* run interpreter */ 272 tgsi_exec_machine_run(machine); 273 274 out_prim_count = 275 machine->Temps[TGSI_EXEC_TEMP_PRIMITIVE_I].xyzw[TGSI_EXEC_TEMP_PRIMITIVE_C].u[0]; 276 277 draw_geometry_fetch_outputs(shader, out_prim_count, 278 &shader->tmp_output); 279} 280 281static void gs_point(struct draw_geometry_shader *shader, 282 int idx) 283{ 284 unsigned indices[1]; 285 286 indices[0] = idx; 287 288 draw_fetch_gs_input(shader, indices, 1, 0); 289 ++shader->in_prim_idx; 290 291 gs_flush(shader, 1); 292} 293 294static void gs_line(struct draw_geometry_shader *shader, 295 int i0, int i1) 296{ 297 unsigned indices[2]; 298 299 indices[0] = i0; 300 indices[1] = i1; 301 302 draw_fetch_gs_input(shader, indices, 2, 0); 303 ++shader->in_prim_idx; 304 305 gs_flush(shader, 1); 306} 307 308static void gs_tri(struct draw_geometry_shader *shader, 309 int i0, int i1, int i2) 310{ 311 unsigned indices[3]; 312 313 indices[0] = i0; 314 indices[1] = i1; 315 indices[2] = i2; 316 317 draw_fetch_gs_input(shader, indices, 3, 0); 318 ++shader->in_prim_idx; 319 320 gs_flush(shader, 1); 321} 322 323#define TRIANGLE(gs,i0,i1,i2) gs_tri(gs,i0,i1,i2) 324#define LINE(gs,i0,i1) gs_line(gs,i0,i1) 325#define POINT(gs,i0) gs_point(gs,i0) 326#define FUNC gs_run 327#include "draw_gs_tmp.h" 328 329int draw_geometry_shader_run(struct draw_geometry_shader *shader, 330 const void *constants[PIPE_MAX_CONSTANT_BUFFERS], 331 const struct draw_vertex_info *input_verts, 332 const struct draw_prim_info *input_prim, 333 struct draw_vertex_info *output_verts, 334 struct draw_prim_info *output_prims ) 335{ 336 const float (*input)[4] = input_verts->verts; 337 unsigned input_stride = input_verts->vertex_size; 338 unsigned vertex_size = input_verts->vertex_size; 339 struct tgsi_exec_machine *machine = shader->machine; 340 unsigned int i; 341 unsigned num_in_primitives = u_gs_prims_for_vertices(input_prim->prim, 342 input_verts->count); 343 344 output_verts->vertex_size = input_verts->vertex_size; 345 output_verts->stride = input_verts->vertex_size; 346 347 output_verts->count = draw_max_output_vertices(draw, 348 input_prim->prim, 349 input_verts->count); 350 351 output_verts->verts = 352 (struct vertex_header *)MALLOC(vert_info.vertex_size * 353 vert_info.count); 354 355 356 357 if (0) debug_printf("%s count = %d (prims = %d)\n", __FUNCTION__, 358 count, num_in_primitives); 359 360 shader->emitted_vertices = 0; 361 shader->emitted_primitives = 0; 362 shader->vertex_size = vertex_size; 363 shader->tmp_output = (float (*)[4])input_verts->verts->data; 364 shader->in_prim_idx = 0; 365 shader->input_vertex_stride = input_stride; 366 shader->input = input; 367 368 for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { 369 machine->Consts[i] = constants[i]; 370 } 371 372 gs_run(shader, pipe_prim, count); 373 374 if (shader->emitted_vertices > 0) { 375 memcpy(output, pipeline_verts->data, 376 shader->info.num_outputs * 4 * sizeof(float) + 377 vertex_size * (shader->emitted_vertices -1)); 378 } 379 380 381 /* Update prim_info: 382 */ 383 output_prims->linear = TRUE; 384 output_prims->elts = NULL; 385 output_prims->primitive_lengths = machine->foo; 386 output_prims->primitive_count = machine->bar; 387 388 return shader->emitted_vertices; 389} 390 391void draw_geometry_shader_delete(struct draw_geometry_shader *shader) 392{ 393 FREE((void*) shader->state.tokens); 394 FREE(shader); 395} 396 397void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, 398 struct draw_context *draw) 399{ 400 if (shader && shader->machine->Tokens != shader->state.tokens) { 401 tgsi_exec_machine_bind_shader(shader->machine, 402 shader->state.tokens, 403 draw->gs.num_samplers, 404 draw->gs.samplers); 405 } 406} 407 408int draw_max_output_vertices(struct draw_context *draw, 409 unsigned pipe_prim, 410 unsigned count) 411{ 412 unsigned alloc_count = align( count, 4 ); 413 414 if (draw->gs.geometry_shader) { 415 unsigned input_primitives = u_gs_prims_for_vertices(pipe_prim, 416 count); 417 /* max GS output is number of input primitives * max output 418 * vertices per each invocation */ 419 unsigned gs_max_verts = input_primitives * 420 draw->gs.geometry_shader->max_output_vertices; 421 if (gs_max_verts > count) 422 alloc_count = align(gs_max_verts, 4); 423 } 424 /*debug_printf("------- alloc count = %d (input = %d)\n", 425 alloc_count, count);*/ 426 return alloc_count; 427} 428