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