draw_pt_fetch_emit.c revision 49becd2d7c751e563ce6be9051dd8e6dad88d1f7
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#include "pipe/p_util.h" 34#include "draw/draw_context.h" 35#include "draw/draw_private.h" 36#include "draw/draw_vbuf.h" 37#include "draw/draw_vertex.h" 38#include "draw/draw_pt.h" 39 40/* The simplest 'middle end' in the new vertex code. 41 * 42 * The responsibilities of a middle end are to: 43 * - perform vertex fetch using 44 * - draw vertex element/buffer state 45 * - a list of fetch indices we received as an input 46 * - run the vertex shader 47 * - cliptest, 48 * - clip coord calculation 49 * - viewport transformation 50 * - if necessary, run the primitive pipeline, passing it: 51 * - a linear array of vertex_header vertices constructed here 52 * - a set of draw indices we received as an input 53 * - otherwise, drive the hw backend, 54 * - allocate space for hardware format vertices 55 * - translate the vertex-shader output vertices to hw format 56 * - calling the backend draw functions. 57 * 58 * For convenience, we provide a helper function to drive the hardware 59 * backend given similar inputs to those required to run the pipeline. 60 * 61 * In the case of passthrough mode, many of these actions are disabled 62 * or noops, so we end up doing: 63 * 64 * - perform vertex fetch 65 * - drive the hw backend 66 * 67 * IE, basically just vertex fetch to post-vs-format vertices, 68 * followed by a call to the backend helper function. 69 */ 70 71 72struct fetch_emit_middle_end { 73 struct draw_pt_middle_end base; 74 struct draw_context *draw; 75 76 struct { 77 const ubyte *ptr; 78 unsigned pitch; 79 void (*fetch)( const void *from, float *attrib); 80 void (*emit)( const float *attrib, float **out ); 81 } fetch[PIPE_MAX_ATTRIBS]; 82 83 unsigned nr_fetch; 84 unsigned hw_vertex_size; 85}; 86 87 88 89static void fetch_R32_FLOAT( const void *from, 90 float *attrib ) 91{ 92 float *f = (float *) from; 93 attrib[0] = f[0]; 94 attrib[1] = 0.0; 95 attrib[2] = 0.0; 96 attrib[3] = 1.0; 97} 98 99 100static void emit_R32_FLOAT( const float *attrib, 101 float **out ) 102{ 103 (*out)[0] = attrib[0]; 104 (*out) += 1; 105} 106 107static void emit_R32G32_FLOAT( const float *attrib, 108 float **out ) 109{ 110 (*out)[0] = attrib[0]; 111 (*out)[1] = attrib[1]; 112 (*out) += 2; 113} 114 115static void emit_R32G32B32_FLOAT( const float *attrib, 116 float **out ) 117{ 118 (*out)[0] = attrib[0]; 119 (*out)[1] = attrib[1]; 120 (*out)[2] = attrib[2]; 121 (*out) += 3; 122} 123 124static void emit_R32G32B32A32_FLOAT( const float *attrib, 125 float **out ) 126{ 127 (*out)[0] = attrib[0]; 128 (*out)[1] = attrib[1]; 129 (*out)[2] = attrib[2]; 130 (*out)[3] = attrib[3]; 131 (*out) += 4; 132} 133 134 135/** 136 * General-purpose fetch from user's vertex arrays, emit to driver's 137 * vertex buffer. 138 * 139 * XXX this is totally temporary. 140 */ 141static void 142fetch_store_general( struct fetch_emit_middle_end *feme, 143 void *out_ptr, 144 const unsigned *fetch_elts, 145 unsigned count ) 146{ 147 float *out = (float *)out_ptr; 148 uint i, j; 149 150 for (i = 0; i < count; i++) { 151 unsigned elt = fetch_elts[i] & ~DRAW_PT_FLAG_MASK; 152 153 for (j = 0; j < feme->nr_fetch; j++) { 154 float attrib[4]; 155 const ubyte *from = (feme->fetch[j].ptr + 156 feme->fetch[j].pitch * elt); 157 158 feme->fetch[j].fetch( from, attrib ); 159 feme->fetch[j].emit( attrib, &out ); 160 } 161 } 162} 163 164 165 166static void fetch_emit_prepare( struct draw_pt_middle_end *middle, 167 unsigned prim, 168 unsigned opt ) 169{ 170 struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; 171 struct draw_context *draw = feme->draw; 172 const struct vertex_info *vinfo; 173 unsigned i; 174 boolean ok; 175 176 177 ok = draw->render->set_primitive( draw->render, 178 prim ); 179 if (!ok) { 180 assert(0); 181 return; 182 } 183 184 /* Must do this after set_primitive() above: 185 */ 186 vinfo = draw->render->get_vertex_info(draw->render); 187 188 189 /* This is unique as it transforms straight from API vertex 190 * information to HW vertices. All other cases go through our 191 * intermediate float[4] format. 192 */ 193 for (i = 0; i < vinfo->num_attribs; i++) { 194 unsigned src_element = vinfo->src_index[i]; 195 unsigned src_buffer = draw->vertex_element[src_element].vertex_buffer_index; 196 197 feme->fetch[i].ptr = ((const ubyte *)draw->user.vbuffer[src_buffer] + 198 draw->vertex_buffer[src_buffer].buffer_offset + 199 draw->vertex_element[src_element].src_offset); 200 201 feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch; 202 203 feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format); 204 205 206 switch (vinfo->emit[i]) { 207 case EMIT_4F: 208 feme->fetch[i].emit = emit_R32G32B32A32_FLOAT; 209 break; 210 case EMIT_3F: 211 feme->fetch[i].emit = emit_R32G32B32_FLOAT; 212 break; 213 case EMIT_2F: 214 feme->fetch[i].emit = emit_R32G32_FLOAT; 215 break; 216 case EMIT_1F: 217 feme->fetch[i].emit = emit_R32_FLOAT; 218 break; 219 case EMIT_1F_PSIZE: 220 feme->fetch[i].ptr = (const ubyte *)&feme->draw->rasterizer->point_size; 221 feme->fetch[i].pitch = 0; 222 feme->fetch[i].fetch = fetch_R32_FLOAT; 223 feme->fetch[i].emit = emit_R32_FLOAT; 224 break; 225 default: 226 assert(0); 227 feme->fetch[i].emit = NULL; 228 break; 229 } 230 } 231 232 feme->nr_fetch = vinfo->num_attribs; 233 feme->hw_vertex_size = vinfo->size * 4; 234} 235 236 237 238 239 240static void fetch_emit_run( struct draw_pt_middle_end *middle, 241 const unsigned *fetch_elts, 242 unsigned fetch_count, 243 const ushort *draw_elts, 244 unsigned draw_count ) 245{ 246 struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; 247 struct draw_context *draw = feme->draw; 248 void *hw_verts; 249 250 /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 251 */ 252 draw_do_flush( draw, DRAW_FLUSH_BACKEND ); 253 254 hw_verts = draw->render->allocate_vertices( draw->render, 255 (ushort)feme->hw_vertex_size, 256 (ushort)fetch_count ); 257 if (!hw_verts) { 258 assert(0); 259 return; 260 } 261 262 263 /* Single routine to fetch vertices and emit HW verts. 264 */ 265 fetch_store_general( feme, 266 hw_verts, 267 fetch_elts, 268 fetch_count ); 269 270 /* XXX: Draw arrays path to avoid re-emitting index list again and 271 * again. 272 */ 273 draw->render->draw( draw->render, 274 draw_elts, 275 draw_count ); 276 277 /* Done -- that was easy, wasn't it: 278 */ 279 draw->render->release_vertices( draw->render, 280 hw_verts, 281 feme->hw_vertex_size, 282 fetch_count ); 283 284} 285 286 287 288static void fetch_emit_finish( struct draw_pt_middle_end *middle ) 289{ 290 /* nothing to do */ 291} 292 293static void fetch_emit_destroy( struct draw_pt_middle_end *middle ) 294{ 295 FREE(middle); 296} 297 298 299struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw ) 300{ 301 struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end ); 302 303 fetch_emit->base.prepare = fetch_emit_prepare; 304 fetch_emit->base.run = fetch_emit_run; 305 fetch_emit->base.finish = fetch_emit_finish; 306 fetch_emit->base.destroy = fetch_emit_destroy; 307 308 fetch_emit->draw = draw; 309 310 return &fetch_emit->base; 311} 312 313