Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvbo_split_copy.c
Go to the documentation of this file.
00001 00002 /* 00003 * Mesa 3-D graphics library 00004 * Version: 6.5 00005 * 00006 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a 00009 * copy of this software and associated documentation files (the "Software"), 00010 * to deal in the Software without restriction, including without limitation 00011 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00012 * and/or sell copies of the Software, and to permit persons to whom the 00013 * Software is furnished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included 00016 * in all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00019 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00021 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00022 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00023 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00024 * 00025 * Authors: 00026 * Keith Whitwell <keith@tungstengraphics.com> 00027 */ 00028 00029 /* Split indexed primitives with per-vertex copying. 00030 */ 00031 00032 #include "main/glheader.h" 00033 #include "main/imports.h" 00034 #include "main/macros.h" 00035 #include "main/enums.h" 00036 #include "main/mtypes.h" 00037 00038 #include "vbo_split.h" 00039 #include "vbo.h" 00040 00041 00042 #define ELT_TABLE_SIZE 16 00043 00044 /* Used for vertex-level splitting of indexed buffers. Note that 00045 * non-indexed primitives may be converted to indexed in some cases 00046 * (eg loops, fans) in order to use this splitting path. 00047 */ 00048 struct copy_context { 00049 00050 GLcontext *ctx; 00051 const struct gl_client_array **array; 00052 const struct _mesa_prim *prim; 00053 GLuint nr_prims; 00054 const struct _mesa_index_buffer *ib; 00055 vbo_draw_func draw; 00056 00057 const struct split_limits *limits; 00058 00059 struct { 00060 GLuint attr; 00061 GLuint size; 00062 const struct gl_client_array *array; 00063 const GLubyte *src_ptr; 00064 00065 struct gl_client_array dstarray; 00066 00067 } varying[VERT_ATTRIB_MAX]; 00068 GLuint nr_varying; 00069 00070 const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX]; 00071 struct _mesa_index_buffer dstib; 00072 00073 GLuint *translated_elt_buf; 00074 const GLuint *srcelt; 00075 00076 /* A baby hash table to avoid re-emitting (some) duplicate 00077 * vertices when splitting indexed primitives. 00078 */ 00079 struct { 00080 GLuint in; 00081 GLuint out; 00082 } vert_cache[ELT_TABLE_SIZE]; 00083 00084 00085 GLuint vertex_size; 00086 GLubyte *dstbuf; 00087 GLubyte *dstptr; /* dstptr == dstbuf + dstelt_max * vertsize */ 00088 GLuint dstbuf_size; /* in vertices */ 00089 GLuint dstbuf_nr; /* count of emitted vertices, also the 00090 * largest value in dstelt. Our 00091 * MaxIndex. 00092 */ 00093 00094 GLuint *dstelt; 00095 GLuint dstelt_nr; 00096 GLuint dstelt_size; 00097 00098 #define MAX_PRIM 32 00099 struct _mesa_prim dstprim[MAX_PRIM]; 00100 GLuint dstprim_nr; 00101 00102 }; 00103 00104 00105 static GLuint type_size( GLenum type ) 00106 { 00107 switch(type) { 00108 case GL_BYTE: return sizeof(GLbyte); 00109 case GL_UNSIGNED_BYTE: return sizeof(GLubyte); 00110 case GL_SHORT: return sizeof(GLshort); 00111 case GL_UNSIGNED_SHORT: return sizeof(GLushort); 00112 case GL_INT: return sizeof(GLint); 00113 case GL_UNSIGNED_INT: return sizeof(GLuint); 00114 case GL_FLOAT: return sizeof(GLfloat); 00115 case GL_DOUBLE: return sizeof(GLdouble); 00116 default: return 0; 00117 } 00118 } 00119 00120 static GLuint attr_size( const struct gl_client_array *array ) 00121 { 00122 return array->Size * type_size(array->Type); 00123 } 00124 00125 00126 /* Starts returning true slightly before the buffer fills, to ensure 00127 * that there is sufficient room for any remaining vertices to finish 00128 * off the prim: 00129 */ 00130 static GLboolean check_flush( struct copy_context *copy ) 00131 { 00132 GLenum mode = copy->dstprim[copy->dstprim_nr].mode; 00133 00134 if (GL_TRIANGLE_STRIP == mode && 00135 copy->dstelt_nr & 1) { /* see bug9962 */ 00136 return GL_FALSE; 00137 } 00138 00139 if (copy->dstbuf_nr + 4 > copy->dstbuf_size) 00140 return GL_TRUE; 00141 00142 if (copy->dstelt_nr + 4 > copy->dstelt_size) 00143 return GL_TRUE; 00144 00145 return GL_FALSE; 00146 } 00147 00148 static void flush( struct copy_context *copy ) 00149 { 00150 GLuint i; 00151 00152 /* Set some counters: 00153 */ 00154 copy->dstib.count = copy->dstelt_nr; 00155 00156 copy->draw( copy->ctx, 00157 copy->dstarray_ptr, 00158 copy->dstprim, 00159 copy->dstprim_nr, 00160 ©->dstib, 00161 0, 00162 copy->dstbuf_nr ); 00163 00164 /* Reset all pointers: 00165 */ 00166 copy->dstprim_nr = 0; 00167 copy->dstelt_nr = 0; 00168 copy->dstbuf_nr = 0; 00169 copy->dstptr = copy->dstbuf; 00170 00171 /* Clear the vertex cache: 00172 */ 00173 for (i = 0; i < ELT_TABLE_SIZE; i++) 00174 copy->vert_cache[i].in = ~0; 00175 } 00176 00177 00178 00179 static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag ) 00180 { 00181 struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 00182 00183 /* _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag); */ 00184 00185 prim->mode = mode; 00186 prim->begin = begin_flag; 00187 } 00188 00189 00190 /* Use a hashtable to attempt to identify recently-emitted vertices 00191 * and avoid re-emitting them. 00192 */ 00193 static GLuint elt(struct copy_context *copy, GLuint elt_idx) 00194 { 00195 GLuint elt = copy->srcelt[elt_idx]; 00196 GLuint slot = elt & (ELT_TABLE_SIZE-1); 00197 00198 /* _mesa_printf("elt %d\n", elt); */ 00199 00200 /* Look up the incoming element in the vertex cache. Re-emit if 00201 * necessary. 00202 */ 00203 if (copy->vert_cache[slot].in != elt) { 00204 GLubyte *csr = copy->dstptr; 00205 GLuint i; 00206 00207 /* _mesa_printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */ 00208 00209 for (i = 0; i < copy->nr_varying; i++) { 00210 const struct gl_client_array *srcarray = copy->varying[i].array; 00211 const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB; 00212 00213 memcpy(csr, srcptr, copy->varying[i].size); 00214 csr += copy->varying[i].size; 00215 00216 if (0) 00217 { 00218 const GLuint *f = (const GLuint *)srcptr; 00219 GLuint j; 00220 _mesa_printf(" varying %d: ", i); 00221 for(j = 0; j < copy->varying[i].size / 4; j++) 00222 _mesa_printf("%x ", f[j]); 00223 _mesa_printf("\n"); 00224 } 00225 00226 } 00227 00228 copy->vert_cache[slot].in = elt; 00229 copy->vert_cache[slot].out = copy->dstbuf_nr++; 00230 copy->dstptr += copy->vertex_size; 00231 00232 assert(csr == copy->dstptr); 00233 assert(copy->dstptr == (copy->dstbuf + 00234 copy->dstbuf_nr * 00235 copy->vertex_size)); 00236 } 00237 /* else */ 00238 /* _mesa_printf(" --> reuse vertex\n"); */ 00239 00240 /* _mesa_printf(" --> emit %d\n", copy->vert_cache[slot].out); */ 00241 copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out; 00242 return check_flush(copy); 00243 } 00244 00245 static void end( struct copy_context *copy, GLboolean end_flag ) 00246 { 00247 struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; 00248 00249 /* _mesa_printf("end (%d)\n", end_flag); */ 00250 00251 prim->end = end_flag; 00252 prim->count = copy->dstelt_nr - prim->start; 00253 00254 if (++copy->dstprim_nr == MAX_PRIM || 00255 check_flush(copy)) 00256 flush(copy); 00257 } 00258 00259 00260 00261 static void replay_elts( struct copy_context *copy ) 00262 { 00263 GLuint i, j, k; 00264 GLboolean split; 00265 00266 for (i = 0; i < copy->nr_prims; i++) { 00267 const struct _mesa_prim *prim = ©->prim[i]; 00268 const GLuint start = prim->start; 00269 GLuint first, incr; 00270 00271 switch (prim->mode) { 00272 00273 case GL_LINE_LOOP: 00274 /* Convert to linestrip and emit the final vertex explicitly, 00275 * but only in the resultant strip that requires it. 00276 */ 00277 j = 0; 00278 while (j != prim->count) { 00279 begin(copy, GL_LINE_STRIP, prim->begin && j == 0); 00280 00281 for (split = GL_FALSE; j != prim->count && !split; j++) 00282 split = elt(copy, start + j); 00283 00284 if (j == prim->count) { 00285 /* Done, emit final line. Split doesn't matter as 00286 * it is always raised a bit early so we can emit 00287 * the last verts if necessary! 00288 */ 00289 if (prim->end) 00290 (void)elt(copy, start + 0); 00291 00292 end(copy, prim->end); 00293 } 00294 else { 00295 /* Wrap 00296 */ 00297 assert(split); 00298 end(copy, 0); 00299 j--; 00300 } 00301 } 00302 break; 00303 00304 case GL_TRIANGLE_FAN: 00305 case GL_POLYGON: 00306 j = 2; 00307 while (j != prim->count) { 00308 begin(copy, prim->mode, prim->begin && j == 0); 00309 00310 split = elt(copy, start+0); 00311 assert(!split); 00312 00313 split = elt(copy, start+j-1); 00314 assert(!split); 00315 00316 for (; j != prim->count && !split; j++) 00317 split = elt(copy, start+j); 00318 00319 end(copy, prim->end && j == prim->count); 00320 00321 if (j != prim->count) { 00322 /* Wrapped the primitive, need to repeat some vertices: 00323 */ 00324 j -= 1; 00325 } 00326 } 00327 break; 00328 00329 default: 00330 (void)split_prim_inplace(prim->mode, &first, &incr); 00331 00332 j = 0; 00333 while (j != prim->count) { 00334 00335 begin(copy, prim->mode, prim->begin && j == 0); 00336 00337 split = 0; 00338 for (k = 0; k < first; k++, j++) 00339 split |= elt(copy, start+j); 00340 00341 assert(!split); 00342 00343 for (; j != prim->count && !split; ) 00344 for (k = 0; k < incr; k++, j++) 00345 split |= elt(copy, start+j); 00346 00347 end(copy, prim->end && j == prim->count); 00348 00349 if (j != prim->count) { 00350 /* Wrapped the primitive, need to repeat some vertices: 00351 */ 00352 assert(j > first - incr); 00353 j -= (first - incr); 00354 } 00355 } 00356 break; 00357 } 00358 } 00359 00360 if (copy->dstprim_nr) 00361 flush(copy); 00362 } 00363 00364 00365 static void replay_init( struct copy_context *copy ) 00366 { 00367 GLcontext *ctx = copy->ctx; 00368 GLuint i; 00369 GLuint offset; 00370 const GLvoid *srcptr; 00371 00372 /* Make a list of varying attributes and their vbo's. Also 00373 * calculate vertex size. 00374 */ 00375 copy->vertex_size = 0; 00376 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 00377 struct gl_buffer_object *vbo = copy->array[i]->BufferObj; 00378 00379 if (copy->array[i]->StrideB == 0) { 00380 copy->dstarray_ptr[i] = copy->array[i]; 00381 } 00382 else { 00383 GLuint j = copy->nr_varying++; 00384 00385 copy->varying[j].attr = i; 00386 copy->varying[j].array = copy->array[i]; 00387 copy->varying[j].size = attr_size(copy->array[i]); 00388 copy->vertex_size += attr_size(copy->array[i]); 00389 00390 if (vbo->Name && !vbo->Pointer) 00391 ctx->Driver.MapBuffer(ctx, 00392 GL_ARRAY_BUFFER_ARB, 00393 GL_WRITE_ONLY, /* XXX */ 00394 vbo); 00395 00396 copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer, 00397 copy->array[i]->Ptr); 00398 00399 copy->dstarray_ptr[i] = ©->varying[j].dstarray; 00400 } 00401 } 00402 00403 /* There must always be an index buffer. Currently require the 00404 * caller convert non-indexed prims to indexed. Could alternately 00405 * do it internally. 00406 */ 00407 if (copy->ib->obj->Name && !copy->ib->obj->Pointer) 00408 ctx->Driver.MapBuffer(ctx, 00409 GL_ARRAY_BUFFER_ARB, /* XXX */ 00410 GL_WRITE_ONLY, /* XXX */ 00411 copy->ib->obj); 00412 00413 srcptr = (const GLubyte *)ADD_POINTERS(copy->ib->obj->Pointer, copy->ib->ptr); 00414 00415 switch (copy->ib->type) { 00416 case GL_UNSIGNED_BYTE: 00417 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count); 00418 copy->srcelt = copy->translated_elt_buf; 00419 00420 for (i = 0; i < copy->ib->count; i++) 00421 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i]; 00422 break; 00423 00424 case GL_UNSIGNED_SHORT: 00425 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count); 00426 copy->srcelt = copy->translated_elt_buf; 00427 00428 for (i = 0; i < copy->ib->count; i++) 00429 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i]; 00430 break; 00431 00432 case GL_UNSIGNED_INT: 00433 copy->translated_elt_buf = NULL; 00434 copy->srcelt = (const GLuint *)srcptr; 00435 break; 00436 } 00437 00438 00439 /* Figure out the maximum allowed vertex buffer size: 00440 */ 00441 if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) { 00442 copy->dstbuf_size = copy->limits->max_verts; 00443 } 00444 else { 00445 copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size; 00446 } 00447 00448 /* Allocate an output vertex buffer: 00449 * 00450 * XXX: This should be a VBO! 00451 */ 00452 copy->dstbuf = _mesa_malloc(copy->dstbuf_size * 00453 copy->vertex_size); 00454 copy->dstptr = copy->dstbuf; 00455 00456 /* Setup new vertex arrays to point into the output buffer: 00457 */ 00458 for (offset = 0, i = 0; i < copy->nr_varying; i++) { 00459 const struct gl_client_array *src = copy->varying[i].array; 00460 struct gl_client_array *dst = ©->varying[i].dstarray; 00461 00462 dst->Size = src->Size; 00463 dst->Type = src->Type; 00464 dst->Stride = copy->vertex_size; 00465 dst->StrideB = copy->vertex_size; 00466 dst->Ptr = copy->dstbuf + offset; 00467 dst->Enabled = GL_TRUE; 00468 dst->Normalized = src->Normalized; 00469 dst->BufferObj = ctx->Array.NullBufferObj; 00470 dst->_MaxElement = copy->dstbuf_size; /* may be less! */ 00471 00472 offset += copy->varying[i].size; 00473 } 00474 00475 /* Allocate an output element list: 00476 */ 00477 copy->dstelt_size = MIN2(65536, 00478 copy->ib->count * 2 + 3); 00479 copy->dstelt_size = MIN2(copy->dstelt_size, 00480 copy->limits->max_indices); 00481 copy->dstelt = _mesa_malloc(sizeof(GLuint) * copy->dstelt_size); 00482 copy->dstelt_nr = 0; 00483 00484 /* Setup the new index buffer to point to the allocated element 00485 * list: 00486 */ 00487 copy->dstib.count = 0; /* duplicates dstelt_nr */ 00488 copy->dstib.type = GL_UNSIGNED_INT; 00489 copy->dstib.obj = ctx->Array.NullBufferObj; 00490 copy->dstib.ptr = copy->dstelt; 00491 } 00492 00493 00494 static void replay_finish( struct copy_context *copy ) 00495 { 00496 GLcontext *ctx = copy->ctx; 00497 GLuint i; 00498 00499 /* Free our vertex and index buffers: 00500 */ 00501 _mesa_free(copy->translated_elt_buf); 00502 _mesa_free(copy->dstbuf); 00503 _mesa_free(copy->dstelt); 00504 00505 /* Unmap VBO's 00506 */ 00507 for (i = 0; i < copy->nr_varying; i++) { 00508 struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj; 00509 00510 if (vbo->Name && vbo->Pointer) 00511 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo); 00512 } 00513 00514 /* Unmap index buffer: 00515 */ 00516 if (copy->ib->obj->Name && copy->ib->obj->Pointer) { 00517 ctx->Driver.UnmapBuffer(ctx, 00518 GL_ARRAY_BUFFER_ARB, /* XXX */ 00519 copy->ib->obj); 00520 } 00521 } 00522 00523 void vbo_split_copy( GLcontext *ctx, 00524 const struct gl_client_array *arrays[], 00525 const struct _mesa_prim *prim, 00526 GLuint nr_prims, 00527 const struct _mesa_index_buffer *ib, 00528 vbo_draw_func draw, 00529 const struct split_limits *limits ) 00530 { 00531 struct copy_context copy; 00532 GLuint i; 00533 00534 memset(©, 0, sizeof(copy)); 00535 00536 /* Require indexed primitives: 00537 */ 00538 assert(ib); 00539 00540 copy.ctx = ctx; 00541 copy.array = arrays; 00542 copy.prim = prim; 00543 copy.nr_prims = nr_prims; 00544 copy.ib = ib; 00545 copy.draw = draw; 00546 copy.limits = limits; 00547 00548 00549 /* Clear the vertex cache: 00550 */ 00551 for (i = 0; i < ELT_TABLE_SIZE; i++) 00552 copy.vert_cache[i].in = ~0; 00553 00554 00555 replay_init(©); 00556 replay_elts(©); 00557 replay_finish(©); 00558 } Generated on Sun May 27 2012 04:20:48 for ReactOS by
1.7.6.1
|