Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvbo_save_api.c
Go to the documentation of this file.
00001 /************************************************************************** 00002 00003 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas. 00004 00005 All Rights Reserved. 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a 00008 copy of this software and associated documentation files (the "Software"), 00009 to deal in the Software without restriction, including without limitation 00010 on the rights to use, copy, modify, merge, publish, distribute, sub 00011 license, and/or sell copies of the Software, and to permit persons to whom 00012 the Software is furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice (including the next 00015 paragraph) shall be included in all copies or substantial portions of the 00016 Software. 00017 00018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 00021 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 00022 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 00023 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 00024 USE OR OTHER DEALINGS IN THE SOFTWARE. 00025 00026 **************************************************************************/ 00027 00028 /* 00029 * Authors: 00030 * Keith Whitwell <keith@tungstengraphics.com> 00031 */ 00032 00033 00034 00035 /* Display list compiler attempts to store lists of vertices with the 00036 * same vertex layout. Additionally it attempts to minimize the need 00037 * for execute-time fixup of these vertex lists, allowing them to be 00038 * cached on hardware. 00039 * 00040 * There are still some circumstances where this can be thwarted, for 00041 * example by building a list that consists of one very long primitive 00042 * (eg Begin(Triangles), 1000 vertices, End), and calling that list 00043 * from inside a different begin/end object (Begin(Lines), CallList, 00044 * End). 00045 * 00046 * In that case the code will have to replay the list as individual 00047 * commands through the Exec dispatch table, or fix up the copied 00048 * vertices at execute-time. 00049 * 00050 * The other case where fixup is required is when a vertex attribute 00051 * is introduced in the middle of a primitive. Eg: 00052 * Begin(Lines) 00053 * TexCoord1f() Vertex2f() 00054 * TexCoord1f() Color3f() Vertex2f() 00055 * End() 00056 * 00057 * If the current value of Color isn't known at compile-time, this 00058 * primitive will require fixup. 00059 * 00060 * 00061 * The list compiler currently doesn't attempt to compile lists 00062 * containing EvalCoord or EvalPoint commands. On encountering one of 00063 * these, compilation falls back to opcodes. 00064 * 00065 * This could be improved to fallback only when a mix of EvalCoord and 00066 * Vertex commands are issued within a single primitive. 00067 */ 00068 00069 00070 #include "main/glheader.h" 00071 #include "main/bufferobj.h" 00072 #include "main/context.h" 00073 #include "main/dlist.h" 00074 #include "main/enums.h" 00075 #include "main/macros.h" 00076 #include "main/api_validate.h" 00077 #include "main/api_arrayelt.h" 00078 #include "main/vtxfmt.h" 00079 #include "glapi/dispatch.h" 00080 00081 #include "vbo_context.h" 00082 00083 00084 #ifdef ERROR 00085 #undef ERROR 00086 #endif 00087 00088 00089 /* An interesting VBO number/name to help with debugging */ 00090 #define VBO_BUF_ID 12345 00091 00092 00093 /* 00094 * NOTE: Old 'parity' issue is gone, but copying can still be 00095 * wrong-footed on replay. 00096 */ 00097 static GLuint _save_copy_vertices( GLcontext *ctx, 00098 const struct vbo_save_vertex_list *node, 00099 const GLfloat *src_buffer) 00100 { 00101 struct vbo_save_context *save = &vbo_context( ctx )->save; 00102 const struct _mesa_prim *prim = &node->prim[node->prim_count-1]; 00103 GLuint nr = prim->count; 00104 GLuint sz = save->vertex_size; 00105 const GLfloat *src = src_buffer + prim->start * sz; 00106 GLfloat *dst = save->copied.buffer; 00107 GLuint ovf, i; 00108 00109 if (prim->end) 00110 return 0; 00111 00112 switch( prim->mode ) 00113 { 00114 case GL_POINTS: 00115 return 0; 00116 case GL_LINES: 00117 ovf = nr&1; 00118 for (i = 0 ; i < ovf ; i++) 00119 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 00120 return i; 00121 case GL_TRIANGLES: 00122 ovf = nr%3; 00123 for (i = 0 ; i < ovf ; i++) 00124 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 00125 return i; 00126 case GL_QUADS: 00127 ovf = nr&3; 00128 for (i = 0 ; i < ovf ; i++) 00129 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 00130 return i; 00131 case GL_LINE_STRIP: 00132 if (nr == 0) 00133 return 0; 00134 else { 00135 _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) ); 00136 return 1; 00137 } 00138 case GL_LINE_LOOP: 00139 case GL_TRIANGLE_FAN: 00140 case GL_POLYGON: 00141 if (nr == 0) 00142 return 0; 00143 else if (nr == 1) { 00144 _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) ); 00145 return 1; 00146 } else { 00147 _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) ); 00148 _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) ); 00149 return 2; 00150 } 00151 case GL_TRIANGLE_STRIP: 00152 case GL_QUAD_STRIP: 00153 switch (nr) { 00154 case 0: ovf = 0; break; 00155 case 1: ovf = 1; break; 00156 default: ovf = 2 + (nr&1); break; 00157 } 00158 for (i = 0 ; i < ovf ; i++) 00159 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); 00160 return i; 00161 default: 00162 assert(0); 00163 return 0; 00164 } 00165 } 00166 00167 00168 static struct vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx ) 00169 { 00170 struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store); 00171 00172 /* obj->Name needs to be non-zero, but won't ever be examined more 00173 * closely than that. In particular these buffers won't be entered 00174 * into the hash and can never be confused with ones visible to the 00175 * user. Perhaps there could be a special number for internal 00176 * buffers: 00177 */ 00178 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, 00179 VBO_BUF_ID, 00180 GL_ARRAY_BUFFER_ARB); 00181 00182 ctx->Driver.BufferData( ctx, 00183 GL_ARRAY_BUFFER_ARB, 00184 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), 00185 NULL, 00186 GL_STATIC_DRAW_ARB, 00187 vertex_store->bufferobj); 00188 00189 vertex_store->buffer = NULL; 00190 vertex_store->used = 0; 00191 vertex_store->refcount = 1; 00192 00193 return vertex_store; 00194 } 00195 00196 static void free_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ) 00197 { 00198 assert(!vertex_store->buffer); 00199 00200 if (vertex_store->bufferobj) { 00201 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); 00202 } 00203 00204 FREE( vertex_store ); 00205 } 00206 00207 static GLfloat *map_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ) 00208 { 00209 assert(vertex_store->bufferobj); 00210 assert(!vertex_store->buffer); 00211 vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, 00212 GL_ARRAY_BUFFER_ARB, /* not used */ 00213 GL_WRITE_ONLY, /* not used */ 00214 vertex_store->bufferobj); 00215 00216 assert(vertex_store->buffer); 00217 return vertex_store->buffer + vertex_store->used; 00218 } 00219 00220 static void unmap_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ) 00221 { 00222 ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj ); 00223 vertex_store->buffer = NULL; 00224 } 00225 00226 00227 static struct vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx ) 00228 { 00229 struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store); 00230 (void) ctx; 00231 store->used = 0; 00232 store->refcount = 1; 00233 return store; 00234 } 00235 00236 static void _save_reset_counters( GLcontext *ctx ) 00237 { 00238 struct vbo_save_context *save = &vbo_context(ctx)->save; 00239 00240 save->prim = save->prim_store->buffer + save->prim_store->used; 00241 save->buffer = (save->vertex_store->buffer + 00242 save->vertex_store->used); 00243 00244 assert(save->buffer == save->vbptr); 00245 00246 if (save->vertex_size) 00247 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 00248 save->vertex_size); 00249 else 00250 save->max_vert = 0; 00251 00252 save->vert_count = 0; 00253 save->prim_count = 0; 00254 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; 00255 save->dangling_attr_ref = 0; 00256 } 00257 00258 00259 /* Insert the active immediate struct onto the display list currently 00260 * being built. 00261 */ 00262 static void _save_compile_vertex_list( GLcontext *ctx ) 00263 { 00264 struct vbo_save_context *save = &vbo_context(ctx)->save; 00265 struct vbo_save_vertex_list *node; 00266 00267 /* Allocate space for this structure in the display list currently 00268 * being compiled. 00269 */ 00270 node = (struct vbo_save_vertex_list *) 00271 _mesa_alloc_instruction(ctx, save->opcode_vertex_list, sizeof(*node)); 00272 00273 if (!node) 00274 return; 00275 00276 /* Duplicate our template, increment refcounts to the storage structs: 00277 */ 00278 _mesa_memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); 00279 node->vertex_size = save->vertex_size; 00280 node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); 00281 node->count = save->vert_count; 00282 node->wrap_count = save->copied.nr; 00283 node->dangling_attr_ref = save->dangling_attr_ref; 00284 node->prim = save->prim; 00285 node->prim_count = save->prim_count; 00286 node->vertex_store = save->vertex_store; 00287 node->prim_store = save->prim_store; 00288 00289 node->vertex_store->refcount++; 00290 node->prim_store->refcount++; 00291 00292 assert(node->attrsz[VBO_ATTRIB_POS] != 0 || 00293 node->count == 0); 00294 00295 if (save->dangling_attr_ref) 00296 ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS; 00297 00298 save->vertex_store->used += save->vertex_size * node->count; 00299 save->prim_store->used += node->prim_count; 00300 00301 00302 /* Copy duplicated vertices 00303 */ 00304 save->copied.nr = _save_copy_vertices( ctx, node, save->buffer ); 00305 00306 00307 /* Deal with GL_COMPILE_AND_EXECUTE: 00308 */ 00309 if (ctx->ExecuteFlag) { 00310 struct _glapi_table *dispatch = GET_DISPATCH(); 00311 00312 _glapi_set_dispatch(ctx->Exec); 00313 00314 vbo_loopback_vertex_list( ctx, 00315 (const GLfloat *)((const char *)save->vertex_store->buffer + 00316 node->buffer_offset), 00317 node->attrsz, 00318 node->prim, 00319 node->prim_count, 00320 node->wrap_count, 00321 node->vertex_size); 00322 00323 _glapi_set_dispatch(dispatch); 00324 } 00325 00326 00327 /* Decide whether the storage structs are full, or can be used for 00328 * the next vertex lists as well. 00329 */ 00330 if (save->vertex_store->used > 00331 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { 00332 00333 /* Unmap old store: 00334 */ 00335 unmap_vertex_store( ctx, save->vertex_store ); 00336 00337 /* Release old reference: 00338 */ 00339 save->vertex_store->refcount--; 00340 assert(save->vertex_store->refcount != 0); 00341 save->vertex_store = NULL; 00342 00343 /* Allocate and map new store: 00344 */ 00345 save->vertex_store = alloc_vertex_store( ctx ); 00346 save->vbptr = map_vertex_store( ctx, save->vertex_store ); 00347 } 00348 00349 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { 00350 save->prim_store->refcount--; 00351 assert(save->prim_store->refcount != 0); 00352 save->prim_store = alloc_prim_store( ctx ); 00353 } 00354 00355 /* Reset our structures for the next run of vertices: 00356 */ 00357 _save_reset_counters( ctx ); 00358 } 00359 00360 00361 /* TODO -- If no new vertices have been stored, don't bother saving 00362 * it. 00363 */ 00364 static void _save_wrap_buffers( GLcontext *ctx ) 00365 { 00366 struct vbo_save_context *save = &vbo_context(ctx)->save; 00367 GLint i = save->prim_count - 1; 00368 GLenum mode; 00369 GLboolean weak; 00370 00371 assert(i < (GLint) save->prim_max); 00372 assert(i >= 0); 00373 00374 /* Close off in-progress primitive. 00375 */ 00376 save->prim[i].count = (save->vert_count - 00377 save->prim[i].start); 00378 mode = save->prim[i].mode; 00379 weak = save->prim[i].weak; 00380 00381 /* store the copied vertices, and allocate a new list. 00382 */ 00383 _save_compile_vertex_list( ctx ); 00384 00385 /* Restart interrupted primitive 00386 */ 00387 save->prim[0].mode = mode; 00388 save->prim[0].weak = weak; 00389 save->prim[0].begin = 0; 00390 save->prim[0].end = 0; 00391 save->prim[0].pad = 0; 00392 save->prim[0].start = 0; 00393 save->prim[0].count = 0; 00394 save->prim_count = 1; 00395 } 00396 00397 00398 00399 /* Called only when buffers are wrapped as the result of filling the 00400 * vertex_store struct. 00401 */ 00402 static void _save_wrap_filled_vertex( GLcontext *ctx ) 00403 { 00404 struct vbo_save_context *save = &vbo_context(ctx)->save; 00405 GLfloat *data = save->copied.buffer; 00406 GLuint i; 00407 00408 /* Emit a glEnd to close off the last vertex list. 00409 */ 00410 _save_wrap_buffers( ctx ); 00411 00412 /* Copy stored stored vertices to start of new list. 00413 */ 00414 assert(save->max_vert - save->vert_count > save->copied.nr); 00415 00416 for (i = 0 ; i < save->copied.nr ; i++) { 00417 _mesa_memcpy( save->vbptr, data, save->vertex_size * sizeof(GLfloat)); 00418 data += save->vertex_size; 00419 save->vbptr += save->vertex_size; 00420 save->vert_count++; 00421 } 00422 } 00423 00424 00425 static void _save_copy_to_current( GLcontext *ctx ) 00426 { 00427 struct vbo_save_context *save = &vbo_context(ctx)->save; 00428 GLuint i; 00429 00430 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 00431 if (save->attrsz[i]) { 00432 save->currentsz[i][0] = save->attrsz[i]; 00433 COPY_CLEAN_4V(save->current[i], 00434 save->attrsz[i], 00435 save->attrptr[i]); 00436 } 00437 } 00438 } 00439 00440 00441 static void _save_copy_from_current( GLcontext *ctx ) 00442 { 00443 struct vbo_save_context *save = &vbo_context(ctx)->save; 00444 GLint i; 00445 00446 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { 00447 switch (save->attrsz[i]) { 00448 case 4: save->attrptr[i][3] = save->current[i][3]; 00449 case 3: save->attrptr[i][2] = save->current[i][2]; 00450 case 2: save->attrptr[i][1] = save->current[i][1]; 00451 case 1: save->attrptr[i][0] = save->current[i][0]; 00452 case 0: break; 00453 } 00454 } 00455 } 00456 00457 00458 00459 00460 /* Flush existing data, set new attrib size, replay copied vertices. 00461 */ 00462 static void _save_upgrade_vertex( GLcontext *ctx, 00463 GLuint attr, 00464 GLuint newsz ) 00465 { 00466 struct vbo_save_context *save = &vbo_context(ctx)->save; 00467 GLuint oldsz; 00468 GLuint i; 00469 GLfloat *tmp; 00470 00471 /* Store the current run of vertices, and emit a GL_END. Emit a 00472 * BEGIN in the new buffer. 00473 */ 00474 if (save->vert_count) 00475 _save_wrap_buffers( ctx ); 00476 else 00477 assert( save->copied.nr == 0 ); 00478 00479 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case 00480 * when the attribute already exists in the vertex and is having 00481 * its size increased. 00482 */ 00483 _save_copy_to_current( ctx ); 00484 00485 /* Fix up sizes: 00486 */ 00487 oldsz = save->attrsz[attr]; 00488 save->attrsz[attr] = newsz; 00489 00490 save->vertex_size += newsz - oldsz; 00491 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 00492 save->vertex_size); 00493 save->vert_count = 0; 00494 00495 /* Recalculate all the attrptr[] values: 00496 */ 00497 for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) { 00498 if (save->attrsz[i]) { 00499 save->attrptr[i] = tmp; 00500 tmp += save->attrsz[i]; 00501 } 00502 else 00503 save->attrptr[i] = NULL; /* will not be dereferenced. */ 00504 } 00505 00506 /* Copy from current to repopulate the vertex with correct values. 00507 */ 00508 _save_copy_from_current( ctx ); 00509 00510 /* Replay stored vertices to translate them to new format here. 00511 * 00512 * If there are copied vertices and the new (upgraded) attribute 00513 * has not been defined before, this list is somewhat degenerate, 00514 * and will need fixup at runtime. 00515 */ 00516 if (save->copied.nr) 00517 { 00518 GLfloat *data = save->copied.buffer; 00519 GLfloat *dest = save->buffer; 00520 GLuint j; 00521 00522 /* Need to note this and fix up at runtime (or loopback): 00523 */ 00524 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { 00525 assert(oldsz == 0); 00526 save->dangling_attr_ref = GL_TRUE; 00527 } 00528 00529 for (i = 0 ; i < save->copied.nr ; i++) { 00530 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { 00531 if (save->attrsz[j]) { 00532 if (j == attr) { 00533 if (oldsz) { 00534 COPY_CLEAN_4V( dest, oldsz, data ); 00535 data += oldsz; 00536 dest += newsz; 00537 } 00538 else { 00539 COPY_SZ_4V( dest, newsz, save->current[attr] ); 00540 dest += newsz; 00541 } 00542 } 00543 else { 00544 GLint sz = save->attrsz[j]; 00545 COPY_SZ_4V( dest, sz, data ); 00546 data += sz; 00547 dest += sz; 00548 } 00549 } 00550 } 00551 } 00552 00553 save->vbptr = dest; 00554 save->vert_count += save->copied.nr; 00555 } 00556 } 00557 00558 static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz ) 00559 { 00560 struct vbo_save_context *save = &vbo_context(ctx)->save; 00561 00562 if (sz > save->attrsz[attr]) { 00563 /* New size is larger. Need to flush existing vertices and get 00564 * an enlarged vertex format. 00565 */ 00566 _save_upgrade_vertex( ctx, attr, sz ); 00567 } 00568 else if (sz < save->active_sz[attr]) { 00569 static GLfloat id[4] = { 0, 0, 0, 1 }; 00570 GLuint i; 00571 00572 /* New size is equal or smaller - just need to fill in some 00573 * zeros. 00574 */ 00575 for (i = sz ; i <= save->attrsz[attr] ; i++) 00576 save->attrptr[attr][i-1] = id[i-1]; 00577 } 00578 00579 save->active_sz[attr] = sz; 00580 } 00581 00582 static void _save_reset_vertex( GLcontext *ctx ) 00583 { 00584 struct vbo_save_context *save = &vbo_context(ctx)->save; 00585 GLuint i; 00586 00587 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { 00588 save->attrsz[i] = 0; 00589 save->active_sz[i] = 0; 00590 } 00591 00592 save->vertex_size = 0; 00593 } 00594 00595 00596 00597 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ ); 00598 00599 00600 /* Only one size for each attribute may be active at once. Eg. if 00601 * Color3f is installed/active, then Color4f may not be, even if the 00602 * vertex actually contains 4 color coordinates. This is because the 00603 * 3f version won't otherwise set color[3] to 1.0 -- this is the job 00604 * of the chooser function when switching between Color4f and Color3f. 00605 */ 00606 #define ATTR( A, N, V0, V1, V2, V3 ) \ 00607 do { \ 00608 struct vbo_save_context *save = &vbo_context(ctx)->save; \ 00609 \ 00610 if (save->active_sz[A] != N) \ 00611 save_fixup_vertex(ctx, A, N); \ 00612 \ 00613 { \ 00614 GLfloat *dest = save->attrptr[A]; \ 00615 if (N>0) dest[0] = V0; \ 00616 if (N>1) dest[1] = V1; \ 00617 if (N>2) dest[2] = V2; \ 00618 if (N>3) dest[3] = V3; \ 00619 } \ 00620 \ 00621 if ((A) == 0) { \ 00622 GLuint i; \ 00623 \ 00624 for (i = 0; i < save->vertex_size; i++) \ 00625 save->vbptr[i] = save->vertex[i]; \ 00626 \ 00627 save->vbptr += save->vertex_size; \ 00628 \ 00629 if (++save->vert_count >= save->max_vert) \ 00630 _save_wrap_filled_vertex( ctx ); \ 00631 } \ 00632 } while (0) 00633 00634 #define TAG(x) _save_##x 00635 00636 #include "vbo_attrib_tmp.h" 00637 00638 00639 00640 00641 /* Cope with EvalCoord/CallList called within a begin/end object: 00642 * -- Flush current buffer 00643 * -- Fallback to opcodes for the rest of the begin/end object. 00644 */ 00645 #define DO_FALLBACK(ctx) \ 00646 do { \ 00647 struct vbo_save_context *save = &vbo_context(ctx)->save; \ 00648 \ 00649 if (save->vert_count || save->prim_count) \ 00650 _save_compile_vertex_list( ctx ); \ 00651 \ 00652 _save_copy_to_current( ctx ); \ 00653 _save_reset_vertex( ctx ); \ 00654 _save_reset_counters( ctx ); \ 00655 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \ 00656 ctx->Driver.SaveNeedFlush = 0; \ 00657 } while (0) 00658 00659 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u ) 00660 { 00661 GET_CURRENT_CONTEXT(ctx); 00662 DO_FALLBACK(ctx); 00663 ctx->Save->EvalCoord1f( u ); 00664 } 00665 00666 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v ) 00667 { 00668 GET_CURRENT_CONTEXT(ctx); 00669 DO_FALLBACK(ctx); 00670 ctx->Save->EvalCoord1fv( v ); 00671 } 00672 00673 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v ) 00674 { 00675 GET_CURRENT_CONTEXT(ctx); 00676 DO_FALLBACK(ctx); 00677 ctx->Save->EvalCoord2f( u, v ); 00678 } 00679 00680 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v ) 00681 { 00682 GET_CURRENT_CONTEXT(ctx); 00683 DO_FALLBACK(ctx); 00684 ctx->Save->EvalCoord2fv( v ); 00685 } 00686 00687 static void GLAPIENTRY _save_EvalPoint1( GLint i ) 00688 { 00689 GET_CURRENT_CONTEXT(ctx); 00690 DO_FALLBACK(ctx); 00691 ctx->Save->EvalPoint1( i ); 00692 } 00693 00694 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j ) 00695 { 00696 GET_CURRENT_CONTEXT(ctx); 00697 DO_FALLBACK(ctx); 00698 ctx->Save->EvalPoint2( i, j ); 00699 } 00700 00701 static void GLAPIENTRY _save_CallList( GLuint l ) 00702 { 00703 GET_CURRENT_CONTEXT(ctx); 00704 DO_FALLBACK(ctx); 00705 ctx->Save->CallList( l ); 00706 } 00707 00708 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v ) 00709 { 00710 GET_CURRENT_CONTEXT(ctx); 00711 DO_FALLBACK(ctx); 00712 ctx->Save->CallLists( n, type, v ); 00713 } 00714 00715 00716 00717 00718 /* This begin is hooked into ... Updating of 00719 * ctx->Driver.CurrentSavePrimitive is already taken care of. 00720 */ 00721 GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode ) 00722 { 00723 struct vbo_save_context *save = &vbo_context(ctx)->save; 00724 00725 GLuint i = save->prim_count++; 00726 00727 assert(i < save->prim_max); 00728 save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK; 00729 save->prim[i].begin = 1; 00730 save->prim[i].end = 0; 00731 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; 00732 save->prim[i].pad = 0; 00733 save->prim[i].start = save->vert_count; 00734 save->prim[i].count = 0; 00735 00736 _mesa_install_save_vtxfmt( ctx, &save->vtxfmt ); 00737 ctx->Driver.SaveNeedFlush = 1; 00738 return GL_TRUE; 00739 } 00740 00741 00742 00743 static void GLAPIENTRY _save_End( void ) 00744 { 00745 GET_CURRENT_CONTEXT( ctx ); 00746 struct vbo_save_context *save = &vbo_context(ctx)->save; 00747 GLint i = save->prim_count - 1; 00748 00749 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 00750 save->prim[i].end = 1; 00751 save->prim[i].count = (save->vert_count - 00752 save->prim[i].start); 00753 00754 if (i == (GLint) save->prim_max - 1) { 00755 _save_compile_vertex_list( ctx ); 00756 assert(save->copied.nr == 0); 00757 } 00758 00759 /* Swap out this vertex format while outside begin/end. Any color, 00760 * etc. received between here and the next begin will be compiled 00761 * as opcodes. 00762 */ 00763 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 00764 } 00765 00766 00767 /* These are all errors as this vtxfmt is only installed inside 00768 * begin/end pairs. 00769 */ 00770 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type, 00771 const GLvoid *indices) 00772 { 00773 GET_CURRENT_CONTEXT(ctx); 00774 (void) mode; (void) count; (void) type; (void) indices; 00775 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); 00776 } 00777 00778 00779 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode, 00780 GLuint start, GLuint end, 00781 GLsizei count, GLenum type, 00782 const GLvoid *indices) 00783 { 00784 GET_CURRENT_CONTEXT(ctx); 00785 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices; 00786 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); 00787 } 00788 00789 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count) 00790 { 00791 GET_CURRENT_CONTEXT(ctx); 00792 (void) mode; (void) start; (void) count; 00793 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" ); 00794 } 00795 00796 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) 00797 { 00798 GET_CURRENT_CONTEXT(ctx); 00799 (void) x1; (void) y1; (void) x2; (void) y2; 00800 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" ); 00801 } 00802 00803 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 ) 00804 { 00805 GET_CURRENT_CONTEXT(ctx); 00806 (void) mode; (void) i1; (void) i2; 00807 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" ); 00808 } 00809 00810 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2, 00811 GLint j1, GLint j2 ) 00812 { 00813 GET_CURRENT_CONTEXT(ctx); 00814 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2; 00815 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" ); 00816 } 00817 00818 static void GLAPIENTRY _save_Begin( GLenum mode ) 00819 { 00820 GET_CURRENT_CONTEXT( ctx ); 00821 (void) mode; 00822 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" ); 00823 } 00824 00825 00826 /* Unlike the functions above, these are to be hooked into the vtxfmt 00827 * maintained in ctx->ListState, active when the list is known or 00828 * suspected to be outside any begin/end primitive. 00829 */ 00830 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) 00831 { 00832 GET_CURRENT_CONTEXT(ctx); 00833 vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK ); 00834 CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 )); 00835 CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 )); 00836 CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 )); 00837 CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 )); 00838 CALL_End(GET_DISPATCH(), ()); 00839 } 00840 00841 00842 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) 00843 { 00844 GET_CURRENT_CONTEXT(ctx); 00845 GLint i; 00846 00847 if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) 00848 return; 00849 00850 _ae_map_vbos( ctx ); 00851 00852 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK ); 00853 00854 for (i = 0; i < count; i++) 00855 CALL_ArrayElement(GET_DISPATCH(), (start + i)); 00856 CALL_End(GET_DISPATCH(), ()); 00857 00858 _ae_unmap_vbos( ctx ); 00859 } 00860 00861 /* Could do better by copying the arrays and element list intact and 00862 * then emitting an indexed prim at runtime. 00863 */ 00864 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, 00865 const GLvoid *indices) 00866 { 00867 GET_CURRENT_CONTEXT(ctx); 00868 GLint i; 00869 00870 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) 00871 return; 00872 00873 _ae_map_vbos( ctx ); 00874 00875 if (ctx->Array.ElementArrayBufferObj->Name) 00876 indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices); 00877 00878 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK ); 00879 00880 switch (type) { 00881 case GL_UNSIGNED_BYTE: 00882 for (i = 0 ; i < count ; i++) 00883 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] )); 00884 break; 00885 case GL_UNSIGNED_SHORT: 00886 for (i = 0 ; i < count ; i++) 00887 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] )); 00888 break; 00889 case GL_UNSIGNED_INT: 00890 for (i = 0 ; i < count ; i++) 00891 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] )); 00892 break; 00893 default: 00894 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 00895 break; 00896 } 00897 00898 CALL_End(GET_DISPATCH(), ()); 00899 00900 _ae_unmap_vbos( ctx ); 00901 } 00902 00903 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode, 00904 GLuint start, GLuint end, 00905 GLsizei count, GLenum type, 00906 const GLvoid *indices) 00907 { 00908 GET_CURRENT_CONTEXT(ctx); 00909 if (_mesa_validate_DrawRangeElements( ctx, mode, 00910 start, end, 00911 count, type, indices )) 00912 _save_OBE_DrawElements( mode, count, type, indices ); 00913 } 00914 00915 00916 00917 00918 00919 static void _save_vtxfmt_init( GLcontext *ctx ) 00920 { 00921 struct vbo_save_context *save = &vbo_context(ctx)->save; 00922 GLvertexformat *vfmt = &save->vtxfmt; 00923 00924 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */ 00925 vfmt->Begin = _save_Begin; 00926 vfmt->Color3f = _save_Color3f; 00927 vfmt->Color3fv = _save_Color3fv; 00928 vfmt->Color4f = _save_Color4f; 00929 vfmt->Color4fv = _save_Color4fv; 00930 vfmt->EdgeFlag = _save_EdgeFlag; 00931 vfmt->End = _save_End; 00932 vfmt->FogCoordfEXT = _save_FogCoordfEXT; 00933 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; 00934 vfmt->Indexf = _save_Indexf; 00935 vfmt->Indexfv = _save_Indexfv; 00936 vfmt->Materialfv = _save_Materialfv; 00937 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; 00938 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; 00939 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; 00940 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; 00941 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; 00942 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; 00943 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; 00944 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; 00945 vfmt->Normal3f = _save_Normal3f; 00946 vfmt->Normal3fv = _save_Normal3fv; 00947 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; 00948 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; 00949 vfmt->TexCoord1f = _save_TexCoord1f; 00950 vfmt->TexCoord1fv = _save_TexCoord1fv; 00951 vfmt->TexCoord2f = _save_TexCoord2f; 00952 vfmt->TexCoord2fv = _save_TexCoord2fv; 00953 vfmt->TexCoord3f = _save_TexCoord3f; 00954 vfmt->TexCoord3fv = _save_TexCoord3fv; 00955 vfmt->TexCoord4f = _save_TexCoord4f; 00956 vfmt->TexCoord4fv = _save_TexCoord4fv; 00957 vfmt->Vertex2f = _save_Vertex2f; 00958 vfmt->Vertex2fv = _save_Vertex2fv; 00959 vfmt->Vertex3f = _save_Vertex3f; 00960 vfmt->Vertex3fv = _save_Vertex3fv; 00961 vfmt->Vertex4f = _save_Vertex4f; 00962 vfmt->Vertex4fv = _save_Vertex4fv; 00963 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; 00964 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; 00965 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; 00966 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; 00967 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; 00968 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; 00969 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; 00970 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; 00971 00972 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; 00973 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; 00974 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; 00975 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; 00976 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; 00977 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; 00978 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; 00979 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; 00980 00981 /* This will all require us to fallback to saving the list as opcodes: 00982 */ 00983 vfmt->CallList = _save_CallList; /* inside begin/end */ 00984 vfmt->CallLists = _save_CallLists; /* inside begin/end */ 00985 vfmt->EvalCoord1f = _save_EvalCoord1f; 00986 vfmt->EvalCoord1fv = _save_EvalCoord1fv; 00987 vfmt->EvalCoord2f = _save_EvalCoord2f; 00988 vfmt->EvalCoord2fv = _save_EvalCoord2fv; 00989 vfmt->EvalPoint1 = _save_EvalPoint1; 00990 vfmt->EvalPoint2 = _save_EvalPoint2; 00991 00992 /* These are all errors as we at least know we are in some sort of 00993 * begin/end pair: 00994 */ 00995 vfmt->EvalMesh1 = _save_EvalMesh1; 00996 vfmt->EvalMesh2 = _save_EvalMesh2; 00997 vfmt->Begin = _save_Begin; 00998 vfmt->Rectf = _save_Rectf; 00999 vfmt->DrawArrays = _save_DrawArrays; 01000 vfmt->DrawElements = _save_DrawElements; 01001 vfmt->DrawRangeElements = _save_DrawRangeElements; 01002 01003 } 01004 01005 01006 void vbo_save_SaveFlushVertices( GLcontext *ctx ) 01007 { 01008 struct vbo_save_context *save = &vbo_context(ctx)->save; 01009 01010 /* Noop when we are actually active: 01011 */ 01012 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM || 01013 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON) 01014 return; 01015 01016 if (save->vert_count || 01017 save->prim_count) 01018 _save_compile_vertex_list( ctx ); 01019 01020 _save_copy_to_current( ctx ); 01021 _save_reset_vertex( ctx ); 01022 _save_reset_counters( ctx ); 01023 ctx->Driver.SaveNeedFlush = 0; 01024 } 01025 01026 void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode ) 01027 { 01028 struct vbo_save_context *save = &vbo_context(ctx)->save; 01029 01030 (void) list; (void) mode; 01031 01032 if (!save->prim_store) 01033 save->prim_store = alloc_prim_store( ctx ); 01034 01035 if (!save->vertex_store) 01036 save->vertex_store = alloc_vertex_store( ctx ); 01037 01038 save->vbptr = map_vertex_store( ctx, save->vertex_store ); 01039 01040 _save_reset_vertex( ctx ); 01041 _save_reset_counters( ctx ); 01042 ctx->Driver.SaveNeedFlush = 0; 01043 } 01044 01045 void vbo_save_EndList( GLcontext *ctx ) 01046 { 01047 struct vbo_save_context *save = &vbo_context(ctx)->save; 01048 01049 /* EndList called inside a (saved) Begin/End pair? 01050 */ 01051 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) { 01052 01053 if (save->prim_count > 0) { 01054 GLint i = save->prim_count - 1; 01055 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; 01056 save->prim[i].end = 0; 01057 save->prim[i].count = (save->vert_count - 01058 save->prim[i].start); 01059 } 01060 01061 /* Make sure this vertex list gets replayed by the "loopback" 01062 * mechanism: 01063 */ 01064 save->dangling_attr_ref = 1; 01065 vbo_save_SaveFlushVertices( ctx ); 01066 01067 /* Swap out this vertex format while outside begin/end. Any color, 01068 * etc. received between here and the next begin will be compiled 01069 * as opcodes. 01070 */ 01071 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 01072 } 01073 01074 unmap_vertex_store( ctx, save->vertex_store ); 01075 01076 assert(save->vertex_size == 0); 01077 } 01078 01079 void vbo_save_BeginCallList( GLcontext *ctx, struct mesa_display_list *dlist ) 01080 { 01081 struct vbo_save_context *save = &vbo_context(ctx)->save; 01082 save->replay_flags |= dlist->flags; 01083 } 01084 01085 void vbo_save_EndCallList( GLcontext *ctx ) 01086 { 01087 struct vbo_save_context *save = &vbo_context(ctx)->save; 01088 01089 if (ctx->ListState.CallDepth == 1) { 01090 /* This is correct: want to keep only the VBO_SAVE_FALLBACK 01091 * flag, if it is set: 01092 */ 01093 save->replay_flags &= VBO_SAVE_FALLBACK; 01094 } 01095 } 01096 01097 01098 static void vbo_destroy_vertex_list( GLcontext *ctx, void *data ) 01099 { 01100 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; 01101 (void) ctx; 01102 01103 if ( --node->vertex_store->refcount == 0 ) 01104 free_vertex_store( ctx, node->vertex_store ); 01105 01106 if ( --node->prim_store->refcount == 0 ) 01107 FREE( node->prim_store ); 01108 } 01109 01110 01111 static void vbo_print_vertex_list( GLcontext *ctx, void *data ) 01112 { 01113 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; 01114 GLuint i; 01115 (void) ctx; 01116 01117 _mesa_debug(NULL, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", 01118 node->count, 01119 node->prim_count, 01120 node->vertex_size); 01121 01122 for (i = 0 ; i < node->prim_count ; i++) { 01123 struct _mesa_prim *prim = &node->prim[i]; 01124 _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", 01125 i, 01126 _mesa_lookup_enum_by_nr(prim->mode), 01127 prim->weak ? " (weak)" : "", 01128 prim->start, 01129 prim->start + prim->count, 01130 (prim->begin) ? "BEGIN" : "(wrap)", 01131 (prim->end) ? "END" : "(wrap)"); 01132 } 01133 } 01134 01135 01136 static void _save_current_init( GLcontext *ctx ) 01137 { 01138 struct vbo_save_context *save = &vbo_context(ctx)->save; 01139 GLint i; 01140 01141 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { 01142 const GLuint j = i - VBO_ATTRIB_POS; 01143 ASSERT(j < VERT_ATTRIB_MAX); 01144 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; 01145 save->current[i] = ctx->ListState.CurrentAttrib[j]; 01146 } 01147 01148 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { 01149 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; 01150 ASSERT(j < MAT_ATTRIB_MAX); 01151 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; 01152 save->current[i] = ctx->ListState.CurrentMaterial[j]; 01153 } 01154 } 01155 01159 void vbo_save_api_init( struct vbo_save_context *save ) 01160 { 01161 GLcontext *ctx = save->ctx; 01162 GLuint i; 01163 01164 save->opcode_vertex_list = 01165 _mesa_alloc_opcode( ctx, 01166 sizeof(struct vbo_save_vertex_list), 01167 vbo_save_playback_vertex_list, 01168 vbo_destroy_vertex_list, 01169 vbo_print_vertex_list ); 01170 01171 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; 01172 01173 _save_vtxfmt_init( ctx ); 01174 _save_current_init( ctx ); 01175 01176 /* These will actually get set again when binding/drawing */ 01177 for (i = 0; i < VBO_ATTRIB_MAX; i++) 01178 save->inputs[i] = &save->arrays[i]; 01179 01180 /* Hook our array functions into the outside-begin-end vtxfmt in 01181 * ctx->ListState. 01182 */ 01183 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; 01184 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; 01185 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; 01186 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; 01187 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); 01188 } 01189 Generated on Sun May 27 2012 04:20:48 for ReactOS by
1.7.6.1
|