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