📄 vbo_save_api.c
字号:
/**************************************************************************Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.All Rights Reserved.Permission is hereby granted, free of charge, to any person obtaining acopy of this software and associated documentation files (the "Software"),to deal in the Software without restriction, including without limitationon the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whomthe Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice (including the nextparagraph) shall be included in all copies or substantial portions of theSoftware.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALLTUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OROTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THEUSE OR OTHER DEALINGS IN THE SOFTWARE.**************************************************************************//* * Authors: * Keith Whitwell <keith@tungstengraphics.com> *//* Display list compiler attempts to store lists of vertices with the * same vertex layout. Additionally it attempts to minimize the need * for execute-time fixup of these vertex lists, allowing them to be * cached on hardware. * * There are still some circumstances where this can be thwarted, for * example by building a list that consists of one very long primitive * (eg Begin(Triangles), 1000 vertices, End), and calling that list * from inside a different begin/end object (Begin(Lines), CallList, * End). * * In that case the code will have to replay the list as individual * commands through the Exec dispatch table, or fix up the copied * vertices at execute-time. * * The other case where fixup is required is when a vertex attribute * is introduced in the middle of a primitive. Eg: * Begin(Lines) * TexCoord1f() Vertex2f() * TexCoord1f() Color3f() Vertex2f() * End() * * If the current value of Color isn't known at compile-time, this * primitive will require fixup. * * * The list compiler currently doesn't attempt to compile lists * containing EvalCoord or EvalPoint commands. On encountering one of * these, compilation falls back to opcodes. * * This could be improved to fallback only when a mix of EvalCoord and * Vertex commands are issued within a single primitive. */#include "main/glheader.h"#include "main/bufferobj.h"#include "main/context.h"#include "main/dlist.h"#include "main/enums.h"#include "main/macros.h"#include "main/api_validate.h"#include "main/api_arrayelt.h"#include "main/vtxfmt.h"#include "glapi/dispatch.h"#include "vbo_context.h"#ifdef ERROR#undef ERROR#endif/* An interesting VBO number/name to help with debugging */#define VBO_BUF_ID 12345/* * NOTE: Old 'parity' issue is gone, but copying can still be * wrong-footed on replay. */static GLuint _save_copy_vertices( GLcontext *ctx, const struct vbo_save_vertex_list *node, const GLfloat *src_buffer){ struct vbo_save_context *save = &vbo_context( ctx )->save; const struct _mesa_prim *prim = &node->prim[node->prim_count-1]; GLuint nr = prim->count; GLuint sz = save->vertex_size; const GLfloat *src = src_buffer + prim->start * sz; GLfloat *dst = save->copied.buffer; GLuint ovf, i; if (prim->end) return 0; switch( prim->mode ) { case GL_POINTS: return 0; case GL_LINES: ovf = nr&1; for (i = 0 ; i < ovf ; i++) _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); return i; case GL_TRIANGLES: ovf = nr%3; for (i = 0 ; i < ovf ; i++) _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); return i; case GL_QUADS: ovf = nr&3; for (i = 0 ; i < ovf ; i++) _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); return i; case GL_LINE_STRIP: if (nr == 0) return 0; else { _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) ); return 1; } case GL_LINE_LOOP: case GL_TRIANGLE_FAN: case GL_POLYGON: if (nr == 0) return 0; else if (nr == 1) { _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) ); return 1; } else { _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) ); _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) ); return 2; } case GL_TRIANGLE_STRIP: case GL_QUAD_STRIP: switch (nr) { case 0: ovf = 0; break; case 1: ovf = 1; break; default: ovf = 2 + (nr&1); break; } for (i = 0 ; i < ovf ; i++) _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); return i; default: assert(0); return 0; }}static struct vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx ){ struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store); /* obj->Name needs to be non-zero, but won't ever be examined more * closely than that. In particular these buffers won't be entered * into the hash and can never be confused with ones visible to the * user. Perhaps there could be a special number for internal * buffers: */ vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID, GL_ARRAY_BUFFER_ARB); ctx->Driver.BufferData( ctx, GL_ARRAY_BUFFER_ARB, VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), NULL, GL_STATIC_DRAW_ARB, vertex_store->bufferobj); vertex_store->buffer = NULL; vertex_store->used = 0; vertex_store->refcount = 1; return vertex_store;}static void free_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ){ assert(!vertex_store->buffer); if (vertex_store->bufferobj) { _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); } FREE( vertex_store );}static GLfloat *map_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ){ assert(vertex_store->bufferobj); assert(!vertex_store->buffer); vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, /* not used */ GL_WRITE_ONLY, /* not used */ vertex_store->bufferobj); assert(vertex_store->buffer); return vertex_store->buffer + vertex_store->used;}static void unmap_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store ){ ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj ); vertex_store->buffer = NULL;}static struct vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx ){ struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store); (void) ctx; store->used = 0; store->refcount = 1; return store;}static void _save_reset_counters( GLcontext *ctx ){ struct vbo_save_context *save = &vbo_context(ctx)->save; save->prim = save->prim_store->buffer + save->prim_store->used; save->buffer = (save->vertex_store->buffer + save->vertex_store->used); assert(save->buffer == save->vbptr); if (save->vertex_size) save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / save->vertex_size); else save->max_vert = 0; save->vert_count = 0; save->prim_count = 0; save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; save->dangling_attr_ref = 0;}/* Insert the active immediate struct onto the display list currently * being built. */static void _save_compile_vertex_list( GLcontext *ctx ){ struct vbo_save_context *save = &vbo_context(ctx)->save; struct vbo_save_vertex_list *node; /* Allocate space for this structure in the display list currently * being compiled. */ node = (struct vbo_save_vertex_list *) _mesa_alloc_instruction(ctx, save->opcode_vertex_list, sizeof(*node)); if (!node) return; /* Duplicate our template, increment refcounts to the storage structs: */ _mesa_memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); node->vertex_size = save->vertex_size; node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); node->count = save->vert_count; node->wrap_count = save->copied.nr; node->dangling_attr_ref = save->dangling_attr_ref; node->prim = save->prim; node->prim_count = save->prim_count; node->vertex_store = save->vertex_store; node->prim_store = save->prim_store; node->vertex_store->refcount++; node->prim_store->refcount++; assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0); if (save->dangling_attr_ref) ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS; save->vertex_store->used += save->vertex_size * node->count; save->prim_store->used += node->prim_count; /* Copy duplicated vertices */ save->copied.nr = _save_copy_vertices( ctx, node, save->buffer ); /* Deal with GL_COMPILE_AND_EXECUTE: */ if (ctx->ExecuteFlag) { struct _glapi_table *dispatch = GET_DISPATCH(); _glapi_set_dispatch(ctx->Exec); vbo_loopback_vertex_list( ctx, (const GLfloat *)((const char *)save->vertex_store->buffer + node->buffer_offset), node->attrsz, node->prim, node->prim_count, node->wrap_count, node->vertex_size); _glapi_set_dispatch(dispatch); } /* Decide whether the storage structs are full, or can be used for * the next vertex lists as well. */ if (save->vertex_store->used > VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { /* Unmap old store: */ unmap_vertex_store( ctx, save->vertex_store ); /* Release old reference: */ save->vertex_store->refcount--; assert(save->vertex_store->refcount != 0); save->vertex_store = NULL; /* Allocate and map new store: */ save->vertex_store = alloc_vertex_store( ctx ); save->vbptr = map_vertex_store( ctx, save->vertex_store ); } if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { save->prim_store->refcount--; assert(save->prim_store->refcount != 0); save->prim_store = alloc_prim_store( ctx ); } /* Reset our structures for the next run of vertices: */ _save_reset_counters( ctx );}/* TODO -- If no new vertices have been stored, don't bother saving * it. */static void _save_wrap_buffers( GLcontext *ctx ){ struct vbo_save_context *save = &vbo_context(ctx)->save; GLint i = save->prim_count - 1; GLenum mode; GLboolean weak; assert(i < (GLint) save->prim_max); assert(i >= 0); /* Close off in-progress primitive. */ save->prim[i].count = (save->vert_count - save->prim[i].start); mode = save->prim[i].mode; weak = save->prim[i].weak; /* store the copied vertices, and allocate a new list. */ _save_compile_vertex_list( ctx ); /* Restart interrupted primitive */ save->prim[0].mode = mode; save->prim[0].weak = weak; save->prim[0].begin = 0; save->prim[0].end = 0; save->prim[0].pad = 0; save->prim[0].start = 0; save->prim[0].count = 0; save->prim_count = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -