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