t_draw.c revision 4a49301e
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keith@tungstengraphics.com> 26 */ 27 28#include "main/glheader.h" 29#include "main/context.h" 30#include "main/imports.h" 31#include "main/mtypes.h" 32#include "main/macros.h" 33#include "main/enums.h" 34 35#include "t_context.h" 36#include "tnl.h" 37 38 39 40static GLubyte *get_space(GLcontext *ctx, GLuint bytes) 41{ 42 TNLcontext *tnl = TNL_CONTEXT(ctx); 43 GLubyte *space = _mesa_malloc(bytes); 44 45 tnl->block[tnl->nr_blocks++] = space; 46 return space; 47} 48 49 50static void free_space(GLcontext *ctx) 51{ 52 TNLcontext *tnl = TNL_CONTEXT(ctx); 53 GLuint i; 54 for (i = 0; i < tnl->nr_blocks; i++) 55 _mesa_free(tnl->block[i]); 56 tnl->nr_blocks = 0; 57} 58 59 60/* Convert the incoming array to GLfloats. Understands the 61 * array->Normalized flag and selects the correct conversion method. 62 */ 63#define CONVERT( TYPE, MACRO ) do { \ 64 GLuint i, j; \ 65 if (input->Normalized) { \ 66 for (i = 0; i < count; i++) { \ 67 const TYPE *in = (TYPE *)ptr; \ 68 for (j = 0; j < sz; j++) { \ 69 *fptr++ = MACRO(*in); \ 70 in++; \ 71 } \ 72 ptr += input->StrideB; \ 73 } \ 74 } else { \ 75 for (i = 0; i < count; i++) { \ 76 const TYPE *in = (TYPE *)ptr; \ 77 for (j = 0; j < sz; j++) { \ 78 *fptr++ = (GLfloat)(*in); \ 79 in++; \ 80 } \ 81 ptr += input->StrideB; \ 82 } \ 83 } \ 84} while (0) 85 86 87/** 88 * Convert array of BGRA/GLubyte[4] values to RGBA/float[4] 89 * \param ptr input/ubyte array 90 * \param fptr output/float array 91 */ 92static void 93convert_bgra_to_float(const struct gl_client_array *input, 94 const GLubyte *ptr, GLfloat *fptr, 95 GLuint count ) 96{ 97 GLuint i; 98 assert(input->Normalized); 99 assert(input->Size == 4); 100 for (i = 0; i < count; i++) { 101 const GLubyte *in = (GLubyte *) ptr; /* in is in BGRA order */ 102 *fptr++ = UBYTE_TO_FLOAT(in[2]); /* red */ 103 *fptr++ = UBYTE_TO_FLOAT(in[1]); /* green */ 104 *fptr++ = UBYTE_TO_FLOAT(in[0]); /* blue */ 105 *fptr++ = UBYTE_TO_FLOAT(in[3]); /* alpha */ 106 ptr += input->StrideB; 107 } 108} 109 110 111/* Adjust pointer to point at first requested element, convert to 112 * floating point, populate VB->AttribPtr[]. 113 */ 114static void _tnl_import_array( GLcontext *ctx, 115 GLuint attrib, 116 GLuint count, 117 const struct gl_client_array *input, 118 const GLubyte *ptr ) 119{ 120 TNLcontext *tnl = TNL_CONTEXT(ctx); 121 struct vertex_buffer *VB = &tnl->vb; 122 GLuint stride = input->StrideB; 123 124 if (input->Type != GL_FLOAT) { 125 const GLuint sz = input->Size; 126 GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat)); 127 GLfloat *fptr = (GLfloat *)buf; 128 129 switch (input->Type) { 130 case GL_BYTE: 131 CONVERT(GLbyte, BYTE_TO_FLOAT); 132 break; 133 case GL_UNSIGNED_BYTE: 134 if (input->Format == GL_BGRA) { 135 /* See GL_EXT_vertex_array_bgra */ 136 convert_bgra_to_float(input, ptr, fptr, count); 137 } 138 else { 139 CONVERT(GLubyte, UBYTE_TO_FLOAT); 140 } 141 break; 142 case GL_SHORT: 143 CONVERT(GLshort, SHORT_TO_FLOAT); 144 break; 145 case GL_UNSIGNED_SHORT: 146 CONVERT(GLushort, USHORT_TO_FLOAT); 147 break; 148 case GL_INT: 149 CONVERT(GLint, INT_TO_FLOAT); 150 break; 151 case GL_UNSIGNED_INT: 152 CONVERT(GLuint, UINT_TO_FLOAT); 153 break; 154 case GL_DOUBLE: 155 CONVERT(GLdouble, (GLfloat)); 156 break; 157 default: 158 assert(0); 159 break; 160 } 161 162 ptr = buf; 163 stride = sz * sizeof(GLfloat); 164 } 165 166 VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib]; 167 VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr; 168 VB->AttribPtr[attrib]->start = (GLfloat *)ptr; 169 VB->AttribPtr[attrib]->count = count; 170 VB->AttribPtr[attrib]->stride = stride; 171 VB->AttribPtr[attrib]->size = input->Size; 172 173 /* This should die, but so should the whole GLvector4f concept: 174 */ 175 VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) | 176 VEC_NOT_WRITEABLE | 177 (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE)); 178 179 VB->AttribPtr[attrib]->storage = NULL; 180} 181 182#define CLIPVERTS ((6 + MAX_CLIP_PLANES) * 2) 183 184 185static GLboolean *_tnl_import_edgeflag( GLcontext *ctx, 186 const GLvector4f *input, 187 GLuint count) 188{ 189 const GLubyte *ptr = (const GLubyte *)input->data; 190 const GLuint stride = input->stride; 191 GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS); 192 GLboolean *bptr = space; 193 GLuint i; 194 195 for (i = 0; i < count; i++) { 196 *bptr++ = ((GLfloat *)ptr)[0] == 1.0; 197 ptr += stride; 198 } 199 200 return space; 201} 202 203 204static void bind_inputs( GLcontext *ctx, 205 const struct gl_client_array *inputs[], 206 GLint count, 207 struct gl_buffer_object **bo, 208 GLuint *nr_bo ) 209{ 210 TNLcontext *tnl = TNL_CONTEXT(ctx); 211 struct vertex_buffer *VB = &tnl->vb; 212 GLuint i; 213 214 /* Map all the VBOs 215 */ 216 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 217 const void *ptr; 218 219 if (inputs[i]->BufferObj->Name) { 220 if (!inputs[i]->BufferObj->Pointer) { 221 bo[*nr_bo] = inputs[i]->BufferObj; 222 (*nr_bo)++; 223 ctx->Driver.MapBuffer(ctx, 224 GL_ARRAY_BUFFER, 225 GL_READ_ONLY_ARB, 226 inputs[i]->BufferObj); 227 228 assert(inputs[i]->BufferObj->Pointer); 229 } 230 231 ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer, 232 inputs[i]->Ptr); 233 } 234 else 235 ptr = inputs[i]->Ptr; 236 237 /* Just make sure the array is floating point, otherwise convert to 238 * temporary storage. 239 * 240 * XXX: remove the GLvector4f type at some stage and just use 241 * client arrays. 242 */ 243 _tnl_import_array(ctx, i, count, inputs[i], ptr); 244 } 245 246 /* We process only the vertices between min & max index: 247 */ 248 VB->Count = count; 249 250 251 /* Legacy pointers -- remove one day. 252 */ 253 VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS]; 254 VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; 255 VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0]; 256 VB->ColorPtr[1] = NULL; 257 VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR_INDEX]; 258 VB->IndexPtr[1] = NULL; 259 VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1]; 260 VB->SecondaryColorPtr[1] = NULL; 261 VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG]; 262 263 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 264 VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]; 265 } 266 267 /* Clipping and drawing code still requires this to be a packed 268 * array of ubytes which can be written into. TODO: Fix and 269 * remove. 270 */ 271 if (ctx->Polygon.FrontMode != GL_FILL || 272 ctx->Polygon.BackMode != GL_FILL) 273 { 274 VB->EdgeFlag = _tnl_import_edgeflag( ctx, 275 VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG], 276 VB->Count ); 277 } 278 else { 279 /* the data previously pointed to by EdgeFlag may have been freed */ 280 VB->EdgeFlag = NULL; 281 } 282} 283 284 285/* Translate indices to GLuints and store in VB->Elts. 286 */ 287static void bind_indices( GLcontext *ctx, 288 const struct _mesa_index_buffer *ib, 289 struct gl_buffer_object **bo, 290 GLuint *nr_bo) 291{ 292 TNLcontext *tnl = TNL_CONTEXT(ctx); 293 struct vertex_buffer *VB = &tnl->vb; 294 GLuint i; 295 void *ptr; 296 297 if (!ib) { 298 VB->Elts = NULL; 299 return; 300 } 301 302 if (ib->obj->Name && !ib->obj->Pointer) { 303 bo[*nr_bo] = ib->obj; 304 (*nr_bo)++; 305 ctx->Driver.MapBuffer(ctx, 306 GL_ELEMENT_ARRAY_BUFFER, 307 GL_READ_ONLY_ARB, 308 ib->obj); 309 310 assert(ib->obj->Pointer); 311 } 312 313 ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); 314 315 if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) { 316 VB->Elts = (GLuint *) ptr; 317 } 318 else { 319 GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint)); 320 VB->Elts = elts; 321 322 if (ib->type == GL_UNSIGNED_INT) { 323 const GLuint *in = (GLuint *)ptr; 324 for (i = 0; i < ib->count; i++) 325 *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; 326 } 327 else if (ib->type == GL_UNSIGNED_SHORT) { 328 const GLushort *in = (GLushort *)ptr; 329 for (i = 0; i < ib->count; i++) 330 *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; 331 } 332 else { 333 const GLubyte *in = (GLubyte *)ptr; 334 for (i = 0; i < ib->count; i++) 335 *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; 336 } 337 } 338} 339 340static void bind_prims( GLcontext *ctx, 341 const struct _mesa_prim *prim, 342 GLuint nr_prims ) 343{ 344 TNLcontext *tnl = TNL_CONTEXT(ctx); 345 struct vertex_buffer *VB = &tnl->vb; 346 347 VB->Primitive = prim; 348 VB->PrimitiveCount = nr_prims; 349} 350 351static void unmap_vbos( GLcontext *ctx, 352 struct gl_buffer_object **bo, 353 GLuint nr_bo ) 354{ 355 GLuint i; 356 for (i = 0; i < nr_bo; i++) { 357 ctx->Driver.UnmapBuffer(ctx, 358 0, /* target -- I don't see why this would be needed */ 359 bo[i]); 360 } 361} 362 363 364void _tnl_vbo_draw_prims(GLcontext *ctx, 365 const struct gl_client_array *arrays[], 366 const struct _mesa_prim *prim, 367 GLuint nr_prims, 368 const struct _mesa_index_buffer *ib, 369 GLboolean index_bounds_valid, 370 GLuint min_index, 371 GLuint max_index) 372{ 373 if (!index_bounds_valid) 374 vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); 375 376 _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); 377} 378 379/* This is the main entrypoint into the slimmed-down software tnl 380 * module. In a regular swtnl driver, this can be plugged straight 381 * into the vbo->Driver.DrawPrims() callback. 382 */ 383void _tnl_draw_prims( GLcontext *ctx, 384 const struct gl_client_array *arrays[], 385 const struct _mesa_prim *prim, 386 GLuint nr_prims, 387 const struct _mesa_index_buffer *ib, 388 GLuint min_index, 389 GLuint max_index) 390{ 391 TNLcontext *tnl = TNL_CONTEXT(ctx); 392 const GLuint TEST_SPLIT = 0; 393 const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; 394 GLuint max_basevertex = prim->basevertex; 395 GLuint i; 396 397 /* Mesa core state should have been validated already */ 398 assert(ctx->NewState == 0x0); 399 400 for (i = 1; i < nr_prims; i++) 401 max_basevertex = MAX2(max_basevertex, prim[i].basevertex); 402 403 if (0) 404 { 405 _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); 406 for (i = 0; i < nr_prims; i++) 407 _mesa_printf("prim %d: %s start %d count %d\n", i, 408 _mesa_lookup_enum_by_nr(prim[i].mode), 409 prim[i].start, 410 prim[i].count); 411 } 412 413 if (min_index) { 414 /* We always translate away calls with min_index != 0. 415 */ 416 vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, 417 min_index, max_index, 418 _tnl_vbo_draw_prims ); 419 return; 420 } 421 else if (max_index + max_basevertex > max) { 422 /* The software TNL pipeline has a fixed amount of storage for 423 * vertices and it is necessary to split incoming drawing commands 424 * if they exceed that limit. 425 */ 426 struct split_limits limits; 427 limits.max_verts = max; 428 limits.max_vb_size = ~0; 429 limits.max_indices = ~0; 430 431 /* This will split the buffers one way or another and 432 * recursively call back into this function. 433 */ 434 vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 435 0, max_index + prim->basevertex, 436 _tnl_vbo_draw_prims, 437 &limits ); 438 } 439 else { 440 /* May need to map a vertex buffer object for every attribute plus 441 * one for the index buffer. 442 */ 443 struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1]; 444 GLuint nr_bo = 0; 445 446 for (i = 0; i < nr_prims;) { 447 GLuint this_nr_prims; 448 449 /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices 450 * will rebase the elements to the basevertex, and we'll only 451 * emit strings of prims with the same basevertex in one draw call. 452 */ 453 for (this_nr_prims = 1; i + this_nr_prims < nr_prims; 454 this_nr_prims++) { 455 if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) 456 break; 457 } 458 459 /* Binding inputs may imply mapping some vertex buffer objects. 460 * They will need to be unmapped below. 461 */ 462 bind_prims(ctx, &prim[i], this_nr_prims); 463 bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1, 464 bo, &nr_bo); 465 bind_indices(ctx, ib, bo, &nr_bo); 466 467 TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); 468 469 unmap_vbos(ctx, bo, nr_bo); 470 free_space(ctx); 471 472 i += this_nr_prims; 473 } 474 } 475} 476 477