draw_gs.c revision d4ef0f6c67aefe06d8dd647acf8d9005df39a709
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 41#define MAX_PRIM_VERTICES 6 42/* fixme: move it from here */ 43#define MAX_PRIMITIVES 64 44 45boolean 46draw_gs_init( struct draw_context *draw ) 47{ 48 draw->gs.machine = tgsi_exec_machine_create(); 49 if (!draw->gs.machine) 50 return FALSE; 51 52 draw->gs.machine->Primitives = align_malloc( 53 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16); 54 if (!draw->gs.machine->Primitives) 55 return FALSE; 56 memset(draw->gs.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.machine) 65 return; 66 67 align_free(draw->gs.machine->Primitives); 68 69 tgsi_exec_machine_destroy(draw->gs.machine); 70} 71 72void 73draw_gs_set_constants(struct draw_context *draw, 74 unsigned slot, 75 const void *constants, 76 unsigned size) 77{ 78} 79 80 81struct draw_geometry_shader * 82draw_create_geometry_shader(struct draw_context *draw, 83 const struct pipe_shader_state *state) 84{ 85 struct draw_geometry_shader *gs; 86 int i; 87 88 gs = CALLOC_STRUCT(draw_geometry_shader); 89 90 if (!gs) 91 return NULL; 92 93 gs->state = *state; 94 gs->state.tokens = tgsi_dup_tokens(state->tokens); 95 if (!gs->state.tokens) { 96 FREE(gs); 97 return NULL; 98 } 99 100 tgsi_scan_shader(state->tokens, &gs->info); 101 102 /* setup the defaults */ 103 gs->input_primitive = PIPE_PRIM_TRIANGLES; 104 gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP; 105 gs->max_output_vertices = 32; 106 107 for (i = 0; i < gs->info.num_properties; ++i) { 108 if (gs->info.properties[i].name == 109 TGSI_PROPERTY_GS_INPUT_PRIM) 110 gs->input_primitive = gs->info.properties[i].data[0]; 111 else if (gs->info.properties[i].name == 112 TGSI_PROPERTY_GS_OUTPUT_PRIM) 113 gs->output_primitive = gs->info.properties[i].data[0]; 114 else if (gs->info.properties[i].name == 115 TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) 116 gs->max_output_vertices = gs->info.properties[i].data[0]; 117 } 118 119 gs->machine = draw->gs.machine; 120 121 if (gs) 122 { 123 uint i; 124 for (i = 0; i < gs->info.num_outputs; i++) { 125 if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION && 126 gs->info.output_semantic_index[i] == 0) 127 gs->position_output = i; 128 } 129 } 130 131 return gs; 132} 133 134void draw_bind_geometry_shader(struct draw_context *draw, 135 struct draw_geometry_shader *dgs) 136{ 137 draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE); 138 139 if (dgs) { 140 draw->gs.geometry_shader = dgs; 141 draw->gs.num_gs_outputs = dgs->info.num_outputs; 142 draw->gs.position_output = dgs->position_output; 143 draw_geometry_shader_prepare(dgs, draw); 144 } 145 else { 146 draw->gs.geometry_shader = NULL; 147 draw->gs.num_gs_outputs = 0; 148 } 149} 150 151void draw_delete_geometry_shader(struct draw_context *draw, 152 struct draw_geometry_shader *dgs) 153{ 154 FREE(dgs); 155} 156 157static INLINE int num_vertices_for_prim(int prim) 158{ 159 switch(prim) { 160 case PIPE_PRIM_POINTS: 161 return 1; 162 case PIPE_PRIM_LINES: 163 return 2; 164 case PIPE_PRIM_LINE_LOOP: 165 return 2; 166 case PIPE_PRIM_LINE_STRIP: 167 return 2; 168 case PIPE_PRIM_TRIANGLES: 169 return 3; 170 case PIPE_PRIM_TRIANGLE_STRIP: 171 return 3; 172 case PIPE_PRIM_TRIANGLE_FAN: 173 return 3; 174 case PIPE_PRIM_LINES_ADJACENCY: 175 case PIPE_PRIM_LINE_STRIP_ADJACENCY: 176 return 4; 177 case PIPE_PRIM_TRIANGLES_ADJACENCY: 178 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: 179 return 6; 180 default: 181 assert(!"Bad geometry shader input"); 182 return 0; 183 } 184} 185 186static void draw_fetch_geometry_input(struct draw_geometry_shader *shader, 187 int start_primitive, 188 int num_primitives, 189 const float (*input_ptr)[4], 190 unsigned input_vertex_stride, 191 unsigned inputs_from_vs) 192{ 193 struct tgsi_exec_machine *machine = shader->machine; 194 unsigned slot, vs_slot, k, j; 195 unsigned num_vertices = num_vertices_for_prim(shader->input_primitive); 196 int idx = 0; 197 198 for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; slot++) { 199 /*debug_printf("Slot = %d (semantic = %d)\n", slot, 200 shader->info.input_semantic_name[slot]);*/ 201 if (shader->info.input_semantic_name[slot] == 202 TGSI_SEMANTIC_PRIMID) { 203 for (j = 0; j < num_primitives; ++j) { 204 machine->Inputs[idx].xyzw[0].f[j] = (float)start_primitive + j; 205 machine->Inputs[idx].xyzw[1].f[j] = (float)start_primitive + j; 206 machine->Inputs[idx].xyzw[2].f[j] = (float)start_primitive + j; 207 machine->Inputs[idx].xyzw[3].f[j] = (float)start_primitive + j; 208 } 209 ++idx; 210 } else { 211 for (j = 0; j < num_primitives; ++j) { 212 int vidx = idx; 213 const float (*prim_ptr)[4]; 214 /*debug_printf(" %d) Prim (num_verts = %d)\n", start_primitive + j, 215 num_vertices);*/ 216 prim_ptr = (const float (*)[4])( 217 (const char *)input_ptr + 218 (j * num_vertices * input_vertex_stride)); 219 220 for (k = 0; k < num_vertices; ++k, ++vidx) { 221 const float (*input)[4]; 222 input = (const float (*)[4])( 223 (const char *)prim_ptr + (k * input_vertex_stride)); 224 vidx = k * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot; 225 /*debug_printf("\t%d)(%d) Input vert:\n", vidx, k);*/ 226#if 1 227 assert(!util_is_inf_or_nan(input[vs_slot][0])); 228 assert(!util_is_inf_or_nan(input[vs_slot][1])); 229 assert(!util_is_inf_or_nan(input[vs_slot][2])); 230 assert(!util_is_inf_or_nan(input[vs_slot][3])); 231#endif 232 machine->Inputs[vidx].xyzw[0].f[j] = input[vs_slot][0]; 233 machine->Inputs[vidx].xyzw[1].f[j] = input[vs_slot][1]; 234 machine->Inputs[vidx].xyzw[2].f[j] = input[vs_slot][2]; 235 machine->Inputs[vidx].xyzw[3].f[j] = input[vs_slot][3]; 236#if 0 237 debug_printf("\t\t%d %f %f %f %f\n", slot, 238 machine->Inputs[vidx].xyzw[0].f[j], 239 machine->Inputs[vidx].xyzw[1].f[j], 240 machine->Inputs[vidx].xyzw[2].f[j], 241 machine->Inputs[vidx].xyzw[3].f[j]); 242#endif 243 } 244 } 245 ++vs_slot; 246 idx += num_vertices; 247 } 248 } 249} 250/*#define DEBUG_OUTPUTS 1*/ 251static INLINE void 252draw_geometry_fetch_outputs(struct draw_geometry_shader *shader, 253 int num_primitives, 254 float (*output)[4], 255 unsigned vertex_size) 256{ 257 struct tgsi_exec_machine *machine = shader->machine; 258 unsigned prim_idx, j, slot; 259 260 /* Unswizzle all output results. 261 */ 262 /* FIXME: handle all the primitives produced by the gs, not just 263 * the first one 264 unsigned prim_count = 265 mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0];*/ 266 267 shader->emitted_primitives += num_primitives; 268 for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) { 269 unsigned num_verts_per_prim = machine->Primitives[0]; 270 shader->emitted_vertices += num_verts_per_prim; 271 for (j = 0; j < num_verts_per_prim; j++) { 272 int idx = (prim_idx * num_verts_per_prim + j) * 273 shader->info.num_outputs; 274#ifdef DEBUG_OUTPUTS 275 debug_printf("%d) Output vert:\n", idx); 276#endif 277 for (slot = 0; slot < shader->info.num_outputs; slot++) { 278 output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[prim_idx]; 279 output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[prim_idx]; 280 output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[prim_idx]; 281 output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[prim_idx]; 282#ifdef DEBUG_OUTPUTS 283 debug_printf("\t%d: %f %f %f %f\n", slot, 284 output[slot][0], 285 output[slot][1], 286 output[slot][2], 287 output[slot][3]); 288#endif 289 debug_assert(!util_is_inf_or_nan(output[slot][0])); 290 } 291 output = (float (*)[4])((char *)output + vertex_size); 292 } 293 } 294} 295 296int draw_geometry_shader_run(struct draw_geometry_shader *shader, 297 const float (*input)[4], 298 float (*output)[4], 299 const void *constants[PIPE_MAX_CONSTANT_BUFFERS], 300 unsigned count, 301 unsigned input_stride, 302 unsigned vertex_size) 303{ 304 struct tgsi_exec_machine *machine = shader->machine; 305 unsigned int i; 306 unsigned num_vertices = num_vertices_for_prim(shader->input_primitive); 307 unsigned num_primitives = count/num_vertices; 308 unsigned inputs_from_vs = 0; 309 310 shader->emitted_vertices = 0; 311 shader->emitted_primitives = 0; 312 313 for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { 314 machine->Consts[i] = constants[i]; 315 } 316 317 for (i = 0; i < shader->info.num_inputs; ++i) { 318 if (shader->info.input_semantic_name[i] != TGSI_SEMANTIC_PRIMID) 319 ++inputs_from_vs; 320 } 321 322 for (i = 0; i < num_primitives; ++i) { 323 unsigned int max_primitives = 1; 324 325 draw_fetch_geometry_input(shader, i, max_primitives, input, 326 input_stride, inputs_from_vs); 327 328 tgsi_set_exec_mask(machine, 329 1, 330 max_primitives > 1, 331 max_primitives > 2, 332 max_primitives > 3); 333 334 /* run interpreter */ 335 tgsi_exec_machine_run(machine); 336 337 draw_geometry_fetch_outputs(shader, max_primitives, 338 output, vertex_size); 339 } 340 return shader->emitted_vertices; 341} 342 343void draw_geometry_shader_delete(struct draw_geometry_shader *shader) 344{ 345 FREE((void*) shader->state.tokens); 346 FREE(shader); 347} 348 349void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, 350 struct draw_context *draw) 351{ 352 if (shader && shader->machine->Tokens != shader->state.tokens) { 353 tgsi_exec_machine_bind_shader(shader->machine, 354 shader->state.tokens, 355 draw->gs.num_samplers, 356 draw->gs.samplers); 357 } 358} 359