1 /************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 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 /* 29 * Authors: 30 * Keith Whitwell <keith (at) tungstengraphics.com> 31 */ 32 33 34 #include "util/u_math.h" 35 #include "util/u_memory.h" 36 #include "draw/draw_context.h" 37 #include "draw/draw_private.h" 38 #include "draw/draw_vbuf.h" 39 #include "draw/draw_vertex.h" 40 #include "draw/draw_pt.h" 41 #include "draw/draw_vs.h" 42 43 44 struct fetch_shade_emit; 45 46 47 /* Prototype fetch, shade, emit-hw-verts all in one go. 48 */ 49 struct fetch_shade_emit { 50 struct draw_pt_middle_end base; 51 struct draw_context *draw; 52 53 /* Temporaries: 54 */ 55 const float *constants; 56 unsigned pitch[PIPE_MAX_ATTRIBS]; 57 const ubyte *src[PIPE_MAX_ATTRIBS]; 58 unsigned prim; 59 60 struct draw_vs_variant_key key; 61 struct draw_vs_variant *active; 62 63 const struct vertex_info *vinfo; 64 }; 65 66 67 68 static void 69 fse_prepare(struct draw_pt_middle_end *middle, 70 unsigned prim, 71 unsigned opt, 72 unsigned *max_vertices) 73 { 74 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 75 struct draw_context *draw = fse->draw; 76 unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs; 77 const struct vertex_info *vinfo; 78 unsigned i; 79 unsigned nr_vbs = 0; 80 81 /* Can't support geometry shader on this path. 82 */ 83 assert(!draw->gs.geometry_shader); 84 85 draw->render->set_primitive(draw->render, prim); 86 87 /* Must do this after set_primitive() above: 88 */ 89 fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render); 90 91 fse->key.output_stride = vinfo->size * 4; 92 fse->key.nr_outputs = vinfo->num_attribs; 93 fse->key.nr_inputs = num_vs_inputs; 94 95 fse->key.nr_elements = MAX2(fse->key.nr_outputs, /* outputs - translate to hw format */ 96 fse->key.nr_inputs); /* inputs - fetch from api format */ 97 98 fse->key.viewport = !draw->identity_viewport; 99 fse->key.clip = draw->clip_xy || draw->clip_z || draw->clip_user; 100 fse->key.const_vbuffers = 0; 101 102 memset(fse->key.element, 0, 103 fse->key.nr_elements * sizeof(fse->key.element[0])); 104 105 for (i = 0; i < num_vs_inputs; i++) { 106 const struct pipe_vertex_element *src = &draw->pt.vertex_element[i]; 107 fse->key.element[i].in.format = src->src_format; 108 109 /* Consider ignoring these, ie make generated programs 110 * independent of this state: 111 */ 112 fse->key.element[i].in.buffer = src->vertex_buffer_index; 113 fse->key.element[i].in.offset = src->src_offset; 114 nr_vbs = MAX2(nr_vbs, src->vertex_buffer_index + 1); 115 } 116 117 for (i = 0; i < 5 && i < nr_vbs; i++) { 118 if (draw->pt.vertex_buffer[i].stride == 0) 119 fse->key.const_vbuffers |= (1<<i); 120 } 121 122 if (0) debug_printf("%s: lookup const_vbuffers: %x\n", __FUNCTION__, fse->key.const_vbuffers); 123 124 { 125 unsigned dst_offset = 0; 126 127 for (i = 0; i < vinfo->num_attribs; i++) { 128 unsigned emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit); 129 130 /* doesn't handle EMIT_OMIT */ 131 assert(emit_sz != 0); 132 133 /* The elements in the key correspond to vertex shader output 134 * numbers, not to positions in the hw vertex description -- 135 * that's handled by the output_offset field. 136 */ 137 fse->key.element[i].out.format = vinfo->attrib[i].emit; 138 fse->key.element[i].out.vs_output = vinfo->attrib[i].src_index; 139 fse->key.element[i].out.offset = dst_offset; 140 141 dst_offset += emit_sz; 142 assert(fse->key.output_stride >= dst_offset); 143 } 144 } 145 146 fse->active = draw_vs_lookup_variant( draw->vs.vertex_shader, 147 &fse->key ); 148 149 if (!fse->active) { 150 assert(0); 151 return ; 152 } 153 154 if (0) debug_printf("%s: found const_vbuffers: %x\n", __FUNCTION__, 155 fse->active->key.const_vbuffers); 156 157 /* Now set buffer pointers: 158 */ 159 for (i = 0; i < draw->pt.nr_vertex_buffers; i++) { 160 fse->active->set_buffer( fse->active, 161 i, 162 ((const ubyte *) draw->pt.user.vbuffer[i] + 163 draw->pt.vertex_buffer[i].buffer_offset), 164 draw->pt.vertex_buffer[i].stride, 165 draw->pt.max_index ); 166 } 167 168 *max_vertices = (draw->render->max_vertex_buffer_bytes / 169 (vinfo->size * 4)); 170 171 /* Probably need to do this somewhere (or fix exec shader not to 172 * need it): 173 */ 174 if (1) { 175 struct draw_vertex_shader *vs = draw->vs.vertex_shader; 176 vs->prepare(vs, draw); 177 } 178 } 179 180 181 182 static void 183 fse_run_linear(struct draw_pt_middle_end *middle, 184 unsigned start, 185 unsigned count, 186 unsigned prim_flags) 187 { 188 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 189 struct draw_context *draw = fse->draw; 190 char *hw_verts; 191 192 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 193 */ 194 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 195 196 if (!draw->render->allocate_vertices( draw->render, 197 (ushort)fse->key.output_stride, 198 (ushort)count )) 199 goto fail; 200 201 hw_verts = draw->render->map_vertices( draw->render ); 202 if (!hw_verts) 203 goto fail; 204 205 /* Single routine to fetch vertices, run shader and emit HW verts. 206 * Clipping is done elsewhere -- either by the API or on hardware, 207 * or for some other reason not required... 208 */ 209 fse->active->run_linear( fse->active, 210 start, count, 211 hw_verts ); 212 213 if (0) { 214 unsigned i; 215 for (i = 0; i < count; i++) { 216 debug_printf("\n\n%s vertex %d: (stride %d, offset %d)\n", __FUNCTION__, i, 217 fse->key.output_stride, 218 fse->key.output_stride * i); 219 220 draw_dump_emitted_vertex( fse->vinfo, 221 (const uint8_t *)hw_verts + fse->key.output_stride * i ); 222 } 223 } 224 225 draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) ); 226 227 /* Draw arrays path to avoid re-emitting index list again and 228 * again. 229 */ 230 draw->render->draw_arrays( draw->render, 231 0, 232 count ); 233 234 draw->render->release_vertices( draw->render ); 235 236 return; 237 238 fail: 239 debug_warn_once("allocate or map of vertex buffer failed (out of memory?)"); 240 return; 241 } 242 243 244 static void 245 fse_run(struct draw_pt_middle_end *middle, 246 const unsigned *fetch_elts, 247 unsigned fetch_count, 248 const ushort *draw_elts, 249 unsigned draw_count, 250 unsigned prim_flags ) 251 { 252 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 253 struct draw_context *draw = fse->draw; 254 void *hw_verts; 255 256 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 257 */ 258 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 259 260 if (!draw->render->allocate_vertices( draw->render, 261 (ushort)fse->key.output_stride, 262 (ushort)fetch_count )) 263 goto fail; 264 265 hw_verts = draw->render->map_vertices( draw->render ); 266 if (!hw_verts) 267 goto fail; 268 269 /* Single routine to fetch vertices, run shader and emit HW verts. 270 */ 271 fse->active->run_elts( fse->active, 272 fetch_elts, 273 fetch_count, 274 hw_verts ); 275 276 if (0) { 277 unsigned i; 278 for (i = 0; i < fetch_count; i++) { 279 debug_printf("\n\n%s vertex %d:\n", __FUNCTION__, i); 280 draw_dump_emitted_vertex( fse->vinfo, 281 (const uint8_t *)hw_verts + 282 fse->key.output_stride * i ); 283 } 284 } 285 286 draw->render->unmap_vertices( draw->render, 0, (ushort)(fetch_count - 1) ); 287 288 draw->render->draw_elements( draw->render, 289 draw_elts, 290 draw_count ); 291 292 draw->render->release_vertices( draw->render ); 293 return; 294 295 fail: 296 debug_warn_once("allocate or map of vertex buffer failed (out of memory?)"); 297 return; 298 } 299 300 301 302 static boolean 303 fse_run_linear_elts(struct draw_pt_middle_end *middle, 304 unsigned start, 305 unsigned count, 306 const ushort *draw_elts, 307 unsigned draw_count, 308 unsigned prim_flags) 309 { 310 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 311 struct draw_context *draw = fse->draw; 312 char *hw_verts; 313 314 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 315 */ 316 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 317 318 if (!draw->render->allocate_vertices( draw->render, 319 (ushort)fse->key.output_stride, 320 (ushort)count )) 321 return FALSE; 322 323 hw_verts = draw->render->map_vertices( draw->render ); 324 if (!hw_verts) 325 return FALSE; 326 327 /* Single routine to fetch vertices, run shader and emit HW verts. 328 * Clipping is done elsewhere -- either by the API or on hardware, 329 * or for some other reason not required... 330 */ 331 fse->active->run_linear( fse->active, 332 start, count, 333 hw_verts ); 334 335 draw->render->draw_elements( draw->render, 336 draw_elts, 337 draw_count ); 338 339 draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) ); 340 341 draw->render->release_vertices( draw->render ); 342 343 return TRUE; 344 } 345 346 347 348 static void 349 fse_finish(struct draw_pt_middle_end *middle) 350 { 351 } 352 353 354 static void 355 fse_destroy(struct draw_pt_middle_end *middle) 356 { 357 FREE(middle); 358 } 359 360 361 struct draw_pt_middle_end * 362 draw_pt_middle_fse(struct draw_context *draw) 363 { 364 struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit); 365 if (!fse) 366 return NULL; 367 368 fse->base.prepare = fse_prepare; 369 fse->base.run = fse_run; 370 fse->base.run_linear = fse_run_linear; 371 fse->base.run_linear_elts = fse_run_linear_elts; 372 fse->base.finish = fse_finish; 373 fse->base.destroy = fse_destroy; 374 fse->draw = draw; 375 376 return &fse->base; 377 } 378