From 88527b4ee4fadb34fdb90f5ca99d17f3553506af Mon Sep 17 00:00:00 2001 From: havoc Date: Fri, 23 May 2003 18:36:28 +0000 Subject: [PATCH] added R_Mesh_CacheArray (not yet used by anything, but has been tested with some code in gl_rsurf.c), a generic dynamic data caching system intended for vertex arrays git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3020 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_backend.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++ gl_backend.h | 21 +++++ gl_rsurf.c | 14 ++- 3 files changed, 287 insertions(+), 1 deletion(-) diff --git a/gl_backend.c b/gl_backend.c index 53aa3903..3bf290f8 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -175,6 +175,8 @@ void GL_Backend_CheckCvars(void) int polygonelements[768]; +static void R_Mesh_CacheArray_Startup(void); +static void R_Mesh_CacheArray_Shutdown(void); void GL_Backend_AllocArrays(void) { int i, size; @@ -236,12 +238,16 @@ void GL_Backend_AllocArrays(void) CHECKGLERROR } #endif + + R_Mesh_CacheArray_Startup(); } void GL_Backend_FreeArrays(void) { int i; + R_Mesh_CacheArray_Shutdown(); + #ifdef MESH_VAR if (mesh_var) { @@ -1572,3 +1578,250 @@ void R_Mesh_CopyColor4f(const float *color4f, int numverts) memcpy(varray_color4f, color4f, numverts * sizeof(float[4])); } +//=========================================================================== +// vertex array caching subsystem +//=========================================================================== + +typedef struct rcachearraylink_s +{ + struct rcachearraylink_s *next, *prev; + struct rcachearrayitem_s *data; +} +rcachearraylink_t; + +typedef struct rcachearrayitem_s +{ + // the original request structure + rcachearrayrequest_t request; + // active + int active; + // offset into r_mesh_rcachedata + int offset; + // for linking this into the sequential list + rcachearraylink_t sequentiallink; + // for linking this into the lookup list + rcachearraylink_t hashlink; +} +rcachearrayitem_t; + +#define RCACHEARRAY_HASHSIZE 65536 +#define RCACHEARRAY_ITEMS 4096 +#define RCACHEARRAY_DEFAULTSIZE (4 << 20) + +// all active items are linked into this chain in sorted order +static rcachearraylink_t r_mesh_rcachesequentialchain; +// all inactive items are linked into this chain in unknown order +static rcachearraylink_t r_mesh_rcachefreechain; +// all active items are also linked into these chains (using their hashlink) +static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE]; + +// all items are stored here, whether active or inactive +static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS]; + +// size of data buffer +static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE; +// data buffer +static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE]; + +// current state +static int r_mesh_rcachedata_offset; +static rcachearraylink_t *r_mesh_rcachesequentialchain_current; + +static void R_Mesh_CacheArray_Startup(void) +{ + int i; + rcachearraylink_t *l; + // prepare all the linked lists + l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL; + l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL; + memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain)); + for (i = 0;i < RCACHEARRAY_HASHSIZE;i++) + { + l = &r_mesh_rcachechain[i]; + l->next = l->prev = l; + l->data = NULL; + } + memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems)); + for (i = 0;i < RCACHEARRAY_ITEMS;i++) + { + r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i]; + l = &r_mesh_rcacheitems[i].sequentiallink; + l->next = &r_mesh_rcachefreechain; + l->prev = l->next->prev; + l->next->prev = l->prev->next = l; + } + // clear other state + r_mesh_rcachedata_offset = 0; + r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain; +} + +static void R_Mesh_CacheArray_Shutdown(void) +{ +} + +static void R_Mesh_CacheArray_ValidateState(int num) +{ + rcachearraylink_t *l, *lhead; + lhead = &r_mesh_rcachesequentialchain; + if (r_mesh_rcachesequentialchain_current == lhead) + return; + for (l = lhead->next;l != lhead;l = l->next) + if (r_mesh_rcachesequentialchain_current == l) + return; + Sys_Error("%i", num); +} + +int R_Mesh_CacheArray(rcachearrayrequest_t *r) +{ + rcachearraylink_t *l, *lhead, *lnext; + rcachearrayitem_t *d; + int hashindex, offset, offsetend; + + R_Mesh_CacheArray_ValidateState(3); + // calculate a hashindex to choose a cache chain + r->data = NULL; + hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE; + + // is it already cached? + for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next) + { + if (!memcmp(&l->data->request, r, sizeof(l->data->request))) + { + // we have it cached already + r->data = r_mesh_rcachedata + l->data->offset; + return false; + } + } + + // we need to add a new cache item, this means finding a place for the new + // data and making sure we have a free item available, lots of work... + + // check if buffer needs to wrap + if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size) + { + /* + if (r->data_size * 10 > r_mesh_rcachedata_size) + { + // realloc whole cache + } + */ + // reset back to start + r_mesh_rcachedata_offset = 0; + r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain; + } + offset = r_mesh_rcachedata_offset; + r_mesh_rcachedata_offset += r->data_size; + offsetend = r_mesh_rcachedata_offset; + R_Mesh_CacheArray_ValidateState(4); + + { + int n; + for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++); + Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n); + } + + // make room for the new data (remove old items) + lhead = &r_mesh_rcachesequentialchain; + l = r_mesh_rcachesequentialchain_current; + if (l == lhead) + l = l->next; + if (l != lhead) + { + while (l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset) + { + r_mesh_rcachesequentialchain_current = l; + R_Mesh_CacheArray_ValidateState(8); + lnext = l->next; + // if at the end of the chain, wrap around + if (lnext == lhead) + lnext = lnext->next; + r_mesh_rcachesequentialchain_current = lnext; + R_Mesh_CacheArray_ValidateState(10); + + // unlink from sequential chain + l->next->prev = l->prev; + l->prev->next = l->next; + R_Mesh_CacheArray_ValidateState(11); + // link into free chain + l->next = &r_mesh_rcachefreechain; + l->prev = l->next->prev; + l->next->prev = l->prev->next = l; + R_Mesh_CacheArray_ValidateState(12); + + l = &l->data->hashlink; + // unlink from hash chain + l->next->prev = l->prev; + l->prev->next = l->next; + + l = lnext; + r_mesh_rcachesequentialchain_current = l; + R_Mesh_CacheArray_ValidateState(9); + } + } + r_mesh_rcachesequentialchain_current = l; + R_Mesh_CacheArray_ValidateState(5); + // gobble an extra item if we have no free items available + if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain) + { + lnext = l->next; + + // unlink from sequential chain + l->next->prev = l->prev; + l->prev->next = l->next; + // link into free chain + l->next = &r_mesh_rcachefreechain; + l->prev = l->next->prev; + l->next->prev = l->prev->next = l; + + l = &l->data->hashlink; + // unlink from hash chain + l->next->prev = l->prev; + l->prev->next = l->next; + + l = lnext; + } + r_mesh_rcachesequentialchain_current = l; + R_Mesh_CacheArray_ValidateState(6); + + // now take an item from the free chain + l = r_mesh_rcachefreechain.next; + // set it up + d = l->data; + d->request = *r; + d->offset = offset; + // unlink + l->next->prev = l->prev; + l->prev->next = l->next; + // relink to sequential + l->next = r_mesh_rcachesequentialchain_current->prev; + l->prev = l->next->prev; + while (l->next->data && l->data && l->next->data->offset <= d->offset) + { + Con_Printf(">\n"); + l->next = l->next->next; + l->prev = l->prev->next; + } + while (l->prev->data && l->data && l->prev->data->offset >= d->offset) + { + Con_Printf("<\n"); + l->prev = l->prev->prev; + l->next = l->next->prev; + } + l->next->prev = l->prev->next = l; + // also link into hash chain + l = &l->data->hashlink; + l->next = &r_mesh_rcachechain[hashindex]; + l->prev = l->next->prev; + l->prev->next = l; + l->next->prev = l->prev->next = l; + + + //r_mesh_rcachesequentialchain_current = d->sequentiallink.next; + + R_Mesh_CacheArray_ValidateState(7); + // and finally set the data pointer + r->data = r_mesh_rcachedata + d->offset; + // and tell the caller to fill the array + return true; +} + diff --git a/gl_backend.h b/gl_backend.h index 60f5042a..76f40bf5 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -98,5 +98,26 @@ void R_ClearScreen(void); // invoke refresh of frame void SCR_UpdateScreen (void); +// public structure +typedef struct rcachearrayrequest_s +{ + // for use by the code that is requesting the array, these are not + // directly used but merely compared to determine if cache items are + // identical + void *id_pointer1; + void *id_pointer2; + void *id_pointer3; + int id_number1; + int id_number2; + int id_number3; + // size of array data + int data_size; + // array data pointer + void *data; +} +rcachearrayrequest_t; + +int R_Mesh_CacheArray(rcachearrayrequest_t *r); + #endif diff --git a/gl_rsurf.c b/gl_rsurf.c index 02b002e0..84adabbb 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -985,6 +985,10 @@ static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render rmeshstate_t m; int lightmaptexturenum; float cl; + /* + rcachearrayrequest_t request; + memset(&request, 0, sizeof(request)); + */ memset(&m, 0, sizeof(m)); m.blendfunc1 = GL_ONE; m.blendfunc2 = GL_ZERO; @@ -1013,13 +1017,21 @@ static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render } for (mesh = surf->mesh;mesh;mesh = mesh->chain) { - if (gl_mesh_copyarrays.integer) + if (!gl_mesh_copyarrays.integer) { m.pointervertexcount = mesh->numverts; m.pointer_vertex = mesh->vertex3f; m.pointer_texcoord[0] = mesh->texcoordtexture2f; m.pointer_texcoord[1] = mesh->texcoordlightmap2f; m.pointer_texcoord[2] = mesh->texcoorddetail2f; + /* + request.id_pointer1 = ent->model; + request.id_pointer2 = mesh->texcoorddetail2f; + request.data_size = sizeof(float[2]) * mesh->numverts; + if (R_Mesh_CacheArray(&request)) + memcpy(request.data, mesh->texcoorddetail2f, request.data_size); + m.pointer_texcoord[2] = request.data; + */ R_Mesh_State(&m); } else -- 2.39.2