1/************************************************************************** 2 * 3 * Copyright 2007 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 VMWARE 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 <keithw@vmware.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 /* 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 68static void 69fse_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->bypass_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].map + 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 181static void 182fse_bind_parameters(struct draw_pt_middle_end *middle) 183{ 184 /* No-op? */ 185} 186 187 188static void 189fse_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 if (0) { 220 unsigned i; 221 for (i = 0; i < count; i++) { 222 debug_printf("\n\n%s vertex %d: (stride %d, offset %d)\n", __FUNCTION__, i, 223 fse->key.output_stride, 224 fse->key.output_stride * i); 225 226 draw_dump_emitted_vertex( fse->vinfo, 227 (const uint8_t *)hw_verts + fse->key.output_stride * i ); 228 } 229 } 230 231 draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) ); 232 233 /* Draw arrays path to avoid re-emitting index list again and 234 * again. 235 */ 236 draw->render->draw_arrays( draw->render, 237 0, 238 count ); 239 240 draw->render->release_vertices( draw->render ); 241 242 return; 243 244fail: 245 debug_warn_once("allocate or map of vertex buffer failed (out of memory?)"); 246 return; 247} 248 249 250static void 251fse_run(struct draw_pt_middle_end *middle, 252 const unsigned *fetch_elts, 253 unsigned fetch_count, 254 const ushort *draw_elts, 255 unsigned draw_count, 256 unsigned prim_flags ) 257{ 258 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 259 struct draw_context *draw = fse->draw; 260 void *hw_verts; 261 262 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 263 */ 264 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 265 266 if (!draw->render->allocate_vertices( draw->render, 267 (ushort)fse->key.output_stride, 268 (ushort)fetch_count )) 269 goto fail; 270 271 hw_verts = draw->render->map_vertices( draw->render ); 272 if (!hw_verts) 273 goto fail; 274 275 /* Single routine to fetch vertices, run shader and emit HW verts. 276 */ 277 fse->active->run_elts( fse->active, 278 fetch_elts, 279 fetch_count, 280 hw_verts ); 281 282 if (0) { 283 unsigned i; 284 for (i = 0; i < fetch_count; i++) { 285 debug_printf("\n\n%s vertex %d:\n", __FUNCTION__, i); 286 draw_dump_emitted_vertex( fse->vinfo, 287 (const uint8_t *)hw_verts + 288 fse->key.output_stride * i ); 289 } 290 } 291 292 draw->render->unmap_vertices( draw->render, 0, (ushort)(fetch_count - 1) ); 293 294 draw->render->draw_elements( draw->render, 295 draw_elts, 296 draw_count ); 297 298 draw->render->release_vertices( draw->render ); 299 return; 300 301fail: 302 debug_warn_once("allocate or map of vertex buffer failed (out of memory?)"); 303 return; 304} 305 306 307 308static boolean 309fse_run_linear_elts(struct draw_pt_middle_end *middle, 310 unsigned start, 311 unsigned count, 312 const ushort *draw_elts, 313 unsigned draw_count, 314 unsigned prim_flags) 315{ 316 struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; 317 struct draw_context *draw = fse->draw; 318 char *hw_verts; 319 320 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 321 */ 322 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 323 324 if (!draw->render->allocate_vertices( draw->render, 325 (ushort)fse->key.output_stride, 326 (ushort)count )) 327 return FALSE; 328 329 hw_verts = draw->render->map_vertices( draw->render ); 330 if (!hw_verts) 331 return FALSE; 332 333 /* Single routine to fetch vertices, run shader and emit HW verts. 334 * Clipping is done elsewhere -- either by the API or on hardware, 335 * or for some other reason not required... 336 */ 337 fse->active->run_linear( fse->active, 338 start, count, 339 hw_verts ); 340 341 draw->render->draw_elements( draw->render, 342 draw_elts, 343 draw_count ); 344 345 draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) ); 346 347 draw->render->release_vertices( draw->render ); 348 349 return TRUE; 350} 351 352 353 354static void 355fse_finish(struct draw_pt_middle_end *middle) 356{ 357} 358 359 360static void 361fse_destroy(struct draw_pt_middle_end *middle) 362{ 363 FREE(middle); 364} 365 366 367struct draw_pt_middle_end * 368draw_pt_middle_fse(struct draw_context *draw) 369{ 370 struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit); 371 if (!fse) 372 return NULL; 373 374 fse->base.prepare = fse_prepare; 375 fse->base.bind_parameters = fse_bind_parameters; 376 fse->base.run = fse_run; 377 fse->base.run_linear = fse_run_linear; 378 fse->base.run_linear_elts = fse_run_linear_elts; 379 fse->base.finish = fse_finish; 380 fse->base.destroy = fse_destroy; 381 fse->draw = draw; 382 383 return &fse->base; 384} 385