added R_Mesh_CacheArray (not yet used by anything, but has been tested with some...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 23 May 2003 18:36:28 +0000 (18:36 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 23 May 2003 18:36:28 +0000 (18:36 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3020 d7cf8633-e32d-0410-b094-e92efae38249

gl_backend.c
gl_backend.h
gl_rsurf.c

index 53aa390..3bf290f 100644 (file)
@@ -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;
+}
+
index 60f5042..76f40bf 100644 (file)
@@ -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
 
index 02b002e..84adabb 100644 (file)
@@ -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