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