vbo_exec_array.c revision c223c6b663cd5db39ba19c2be74b88cc3b8f53f3
1/************************************************************************** 2 * 3 * Copyright 2003 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#include "main/glheader.h" 29#include "main/context.h" 30#include "main/state.h" 31#include "main/api_validate.h" 32#include "main/api_noop.h" 33#include "glapi/dispatch.h" 34 35#include "vbo_context.h" 36 37/* Compute min and max elements for drawelements calls. 38 */ 39static void get_minmax_index( GLuint count, GLuint type, 40 const GLvoid *indices, 41 GLuint *min_index, 42 GLuint *max_index) 43{ 44 GLint i; 45 46 switch(type) { 47 case GL_UNSIGNED_INT: { 48 const GLuint *ui_indices = (const GLuint *)indices; 49 GLuint max_ui = ui_indices[0]; 50 GLuint min_ui = ui_indices[0]; 51 for (i = 1; i < count; i++) { 52 if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; 53 if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; 54 } 55 *min_index = min_ui; 56 *max_index = max_ui; 57 break; 58 } 59 case GL_UNSIGNED_SHORT: { 60 const GLushort *us_indices = (const GLushort *)indices; 61 GLuint max_us = us_indices[0]; 62 GLuint min_us = us_indices[0]; 63 for (i = 1; i < count; i++) { 64 if (us_indices[i] > max_us) max_us = us_indices[i]; 65 if (us_indices[i] < min_us) min_us = us_indices[i]; 66 } 67 *min_index = min_us; 68 *max_index = max_us; 69 break; 70 } 71 case GL_UNSIGNED_BYTE: { 72 const GLubyte *ub_indices = (const GLubyte *)indices; 73 GLuint max_ub = ub_indices[0]; 74 GLuint min_ub = ub_indices[0]; 75 for (i = 1; i < count; i++) { 76 if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; 77 if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; 78 } 79 *min_index = min_ub; 80 *max_index = max_ub; 81 break; 82 } 83 default: 84 assert(0); 85 break; 86 } 87} 88 89 90/* Just translate the arrayobj into a sane layout. 91 */ 92static void bind_array_obj( GLcontext *ctx ) 93{ 94 struct vbo_context *vbo = vbo_context(ctx); 95 struct vbo_exec_context *exec = &vbo->exec; 96 GLuint i; 97 98 /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array 99 * rather than as individual named arrays. Then this function can 100 * go away. 101 */ 102 exec->array.legacy_array[VERT_ATTRIB_POS] = &ctx->Array.ArrayObj->Vertex; 103 exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &vbo->legacy_currval[VERT_ATTRIB_WEIGHT]; 104 exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &ctx->Array.ArrayObj->Normal; 105 exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &ctx->Array.ArrayObj->Color; 106 exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &ctx->Array.ArrayObj->SecondaryColor; 107 exec->array.legacy_array[VERT_ATTRIB_FOG] = &ctx->Array.ArrayObj->FogCoord; 108 exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &ctx->Array.ArrayObj->Index; 109 exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &ctx->Array.ArrayObj->EdgeFlag; 110 111 for (i = 0; i < 8; i++) 112 exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &ctx->Array.ArrayObj->TexCoord[i]; 113 114 for (i = 0; i < VERT_ATTRIB_MAX; i++) 115 exec->array.generic_array[i] = &ctx->Array.ArrayObj->VertexAttrib[i]; 116 117 exec->array.array_obj = ctx->Array.ArrayObj->Name; 118} 119 120static void recalculate_input_bindings( GLcontext *ctx ) 121{ 122 struct vbo_context *vbo = vbo_context(ctx); 123 struct vbo_exec_context *exec = &vbo->exec; 124 const struct gl_client_array **inputs = &exec->array.inputs[0]; 125 GLuint i; 126 127 exec->array.program_mode = get_program_mode(ctx); 128 exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled; 129 130 switch (exec->array.program_mode) { 131 case VP_NONE: 132 /* When no vertex program is active, we put the material values 133 * into the generic slots. This is the only situation where 134 * material values are available as per-vertex attributes. 135 */ 136 for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { 137 if (exec->array.legacy_array[i]->Enabled) 138 inputs[i] = exec->array.legacy_array[i]; 139 else 140 inputs[i] = &vbo->legacy_currval[i]; 141 } 142 143 for (i = 0; i < MAT_ATTRIB_MAX; i++) { 144 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->mat_currval[i]; 145 } 146 147 /* Could use just about anything, just to fill in the empty 148 * slots: 149 */ 150 for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) 151 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; 152 153 break; 154 case VP_NV: 155 /* NV_vertex_program - attribute arrays alias and override 156 * conventional, legacy arrays. No materials, and the generic 157 * slots are vacant. 158 */ 159 for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { 160 if (exec->array.generic_array[i]->Enabled) 161 inputs[i] = exec->array.generic_array[i]; 162 else if (exec->array.legacy_array[i]->Enabled) 163 inputs[i] = exec->array.legacy_array[i]; 164 else 165 inputs[i] = &vbo->legacy_currval[i]; 166 } 167 168 /* Could use just about anything, just to fill in the empty 169 * slots: 170 */ 171 for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) 172 inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; 173 174 break; 175 case VP_ARB: 176 /* ARB_vertex_program - Only the attribute zero (position) array 177 * aliases and overrides the legacy position array. 178 * 179 * Otherwise, legacy attributes available in the legacy slots, 180 * generic attributes in the generic slots and materials are not 181 * available as per-vertex attributes. 182 */ 183 if (exec->array.generic_array[0]->Enabled) 184 inputs[0] = exec->array.generic_array[0]; 185 else if (exec->array.legacy_array[0]->Enabled) 186 inputs[0] = exec->array.legacy_array[0]; 187 else 188 inputs[0] = &vbo->legacy_currval[0]; 189 190 191 for (i = 1; i <= VERT_ATTRIB_TEX7; i++) { 192 if (exec->array.legacy_array[i]->Enabled) 193 inputs[i] = exec->array.legacy_array[i]; 194 else 195 inputs[i] = &vbo->legacy_currval[i]; 196 } 197 198 for (i = 0; i < 16; i++) { 199 if (exec->array.generic_array[i]->Enabled) 200 inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i]; 201 else 202 inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; 203 } 204 break; 205 } 206} 207 208static void bind_arrays( GLcontext *ctx ) 209{ 210#if 0 211 if (ctx->Array.ArrayObj.Name != exec->array.array_obj) { 212 bind_array_obj(ctx); 213 recalculate_input_bindings(ctx); 214 } 215 else if (exec->array.program_mode != get_program_mode(ctx) || 216 exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) { 217 218 recalculate_input_bindings(ctx); 219 } 220#else 221 bind_array_obj(ctx); 222 recalculate_input_bindings(ctx); 223#endif 224} 225 226 227 228/*********************************************************************** 229 * API functions. 230 */ 231 232static void GLAPIENTRY 233vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) 234{ 235 GET_CURRENT_CONTEXT(ctx); 236 struct vbo_context *vbo = vbo_context(ctx); 237 struct vbo_exec_context *exec = &vbo->exec; 238 struct _mesa_prim prim[1]; 239 240 if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) 241 return; 242 243 FLUSH_CURRENT( ctx, 0 ); 244 245 if (ctx->NewState) 246 _mesa_update_state( ctx ); 247 248 bind_arrays( ctx ); 249 250 prim[0].begin = 1; 251 prim[0].end = 1; 252 prim[0].weak = 0; 253 prim[0].pad = 0; 254 prim[0].mode = mode; 255 prim[0].start = start; 256 prim[0].count = count; 257 prim[0].indexed = 0; 258 259 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count - 1 ); 260} 261 262 263 264static void GLAPIENTRY 265vbo_exec_DrawRangeElements(GLenum mode, 266 GLuint start, GLuint end, 267 GLsizei count, GLenum type, const GLvoid *indices) 268{ 269 GET_CURRENT_CONTEXT(ctx); 270 struct vbo_context *vbo = vbo_context(ctx); 271 struct vbo_exec_context *exec = &vbo->exec; 272 struct _mesa_index_buffer ib; 273 struct _mesa_prim prim[1]; 274 275 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices )) 276 return; 277 278 FLUSH_CURRENT( ctx, 0 ); 279 280 if (ctx->NewState) 281 _mesa_update_state( ctx ); 282 283 bind_arrays( ctx ); 284 285 ib.count = count; 286 ib.type = type; 287 ib.obj = ctx->Array.ElementArrayBufferObj; 288 ib.ptr = indices; 289 290 prim[0].begin = 1; 291 prim[0].end = 1; 292 prim[0].weak = 0; 293 prim[0].pad = 0; 294 prim[0].mode = mode; 295 prim[0].start = 0; 296 prim[0].count = count; 297 prim[0].indexed = 1; 298 299 /* Need to give special consideration to rendering a range of 300 * indices starting somewhere above zero. Typically the 301 * application is issuing multiple DrawRangeElements() to draw 302 * successive primitives layed out linearly in the vertex arrays. 303 * Unless the vertex arrays are all in a VBO (or locked as with 304 * CVA), the OpenGL semantics imply that we need to re-read or 305 * re-upload the vertex data on each draw call. 306 * 307 * In the case of hardware tnl, we want to avoid starting the 308 * upload at zero, as it will mean every draw call uploads an 309 * increasing amount of not-used vertex data. Worse - in the 310 * software tnl module, all those vertices might be transformed and 311 * lit but never rendered. 312 * 313 * If we just upload or transform the vertices in start..end, 314 * however, the indices will be incorrect. 315 * 316 * At this level, we don't know exactly what the requirements of 317 * the backend are going to be, though it will likely boil down to 318 * either: 319 * 320 * 1) Do nothing, everything is in a VBO and is processed once 321 * only. 322 * 323 * 2) Adjust the indices and vertex arrays so that start becomes 324 * zero. 325 * 326 * Rather than doing anything here, I'll provide a helper function 327 * for the latter case elsewhere. 328 */ 329 330 vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, start, end ); 331} 332 333static void GLAPIENTRY 334vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) 335{ 336 GET_CURRENT_CONTEXT(ctx); 337 GLuint min_index = 0; 338 GLuint max_index = 0; 339 340 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) 341 return; 342 343 if (ctx->Array.ElementArrayBufferObj->Name) { 344 const GLvoid *map = ctx->Driver.MapBuffer(ctx, 345 GL_ELEMENT_ARRAY_BUFFER_ARB, 346 GL_READ_ONLY, 347 ctx->Array.ElementArrayBufferObj); 348 349 get_minmax_index(count, type, ADD_POINTERS(map, indices), &min_index, &max_index); 350 351 ctx->Driver.UnmapBuffer(ctx, 352 GL_ELEMENT_ARRAY_BUFFER_ARB, 353 ctx->Array.ElementArrayBufferObj); 354 } 355 else { 356 get_minmax_index(count, type, indices, &min_index, &max_index); 357 } 358 359 vbo_exec_DrawRangeElements(mode, min_index, max_index, count, type, indices); 360} 361 362 363/*********************************************************************** 364 * Initialization 365 */ 366 367 368 369 370void vbo_exec_array_init( struct vbo_exec_context *exec ) 371{ 372#if 1 373 exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; 374 exec->vtxfmt.DrawElements = vbo_exec_DrawElements; 375 exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; 376#else 377 exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays; 378 exec->vtxfmt.DrawElements = _mesa_noop_DrawElements; 379 exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements; 380#endif 381} 382 383 384void vbo_exec_array_destroy( struct vbo_exec_context *exec ) 385{ 386 /* nothing to do */ 387} 388