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