GL_NV_vertex_array_range support added, but disabled by default because for some...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 9 Mar 2003 16:42:54 +0000 (16:42 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 9 Mar 2003 16:42:54 +0000 (16:42 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2819 d7cf8633-e32d-0410-b094-e92efae38249

gl_backend.c
glquake.h
vid.h
vid_glx.c
vid_shared.c

index d41570e..8e0b221 100644 (file)
@@ -2,9 +2,13 @@
 #include "quakedef.h"
 #include "image.h"
 
-cvar_t gl_mesh_maxverts = {0, "gl_mesh_maxverts", "1024"};
+cvar_t gl_mesh_maxverts = {0, "gl_mesh_maxverts", "21760"};
 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1"};
+cvar_t gl_mesh_vertex_array_range = {0, "gl_mesh_vertex_array_range", "0"};
+cvar_t gl_mesh_vertex_array_range_readfrequency = {0, "gl_mesh_vertex_array_range_readfrequency", "0.3"};
+cvar_t gl_mesh_vertex_array_range_writefrequency = {0, "gl_mesh_vertex_array_range_writefrequency", "1"};
+cvar_t gl_mesh_vertex_array_range_priority = {0, "gl_mesh_vertex_array_range_priority", "0.7"};
 cvar_t gl_delayfinish = {CVAR_SAVE, "gl_delayfinish", "0"};
 
 cvar_t r_render = {0, "r_render", "1"};
@@ -76,6 +80,10 @@ GLfloat *varray_vertex, *varray_buf_vertex;
 GLfloat *varray_color, *varray_buf_color;
 GLfloat *varray_texcoord[MAX_TEXTUREUNITS], *varray_buf_texcoord[MAX_TEXTUREUNITS];
 int mesh_maxverts;
+int mesh_var;
+float mesh_var_readfrequency;
+float mesh_var_writefrequency;
+float mesh_var_priority;
 int varray_offset = 0, varray_offsetnext = 0;
 GLuint *varray_buf_elements;
 int mesh_maxelements = 3072;
@@ -121,11 +129,34 @@ void GL_Backend_FreeElementArray(void)
        varray_buf_elements = NULL;
 }
 
+void GL_Backend_CheckCvars(void)
+{
+       // 21760 is (65536 / 3) rounded off to a multiple of 128
+       if (gl_mesh_maxverts.integer < 1024)
+               Cvar_SetValueQuick(&gl_mesh_maxverts, 1024);
+       if (gl_mesh_maxverts.integer > 21760)
+               Cvar_SetValueQuick(&gl_mesh_maxverts, 21760);
+       if (gl_mesh_vertex_array_range.integer && !gl_support_var)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range, 0);
+       if (gl_mesh_vertex_array_range_readfrequency.value < 0)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 0);
+       if (gl_mesh_vertex_array_range_readfrequency.value > 1)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 1);
+       if (gl_mesh_vertex_array_range_writefrequency.value < 0)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 0);
+       if (gl_mesh_vertex_array_range_writefrequency.value > 1)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 1);
+       if (gl_mesh_vertex_array_range_priority.value < 0)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 0);
+       if (gl_mesh_vertex_array_range_priority.value > 1)
+               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 1);
+}
+
 int polygonelements[768];
 
 void GL_Backend_AllocArrays(void)
 {
-       int i;
+       int i, size;
 
        if (!gl_backend_mempool)
        {
@@ -138,53 +169,75 @@ void GL_Backend_AllocArrays(void)
                        varray_buf_texcoord[i] = NULL;
        }
 
+       mesh_maxverts = gl_mesh_maxverts.integer;
+       mesh_var = gl_mesh_vertex_array_range.integer;
+       mesh_var_readfrequency = gl_mesh_vertex_array_range_readfrequency.value;
+       mesh_var_writefrequency = gl_mesh_vertex_array_range_writefrequency.value;
+       mesh_var_priority = gl_mesh_vertex_array_range_priority.value;
+
        if (varray_buf_vertex)
-               Mem_Free(varray_buf_vertex);
+               VID_FreeVertexArrays(varray_buf_vertex);
        varray_buf_vertex = NULL;
-       if (varray_buf_color)
-               Mem_Free(varray_buf_color);
        varray_buf_color = NULL;
-       if (varray_buf_bcolor)
-               Mem_Free(varray_buf_bcolor);
        varray_buf_bcolor = NULL;
        for (i = 0;i < MAX_TEXTUREUNITS;i++)
-       {
-               if (varray_buf_texcoord[i])
-                       Mem_Free(varray_buf_texcoord[i]);
                varray_buf_texcoord[i] = NULL;
-       }
 
-       varray_buf_vertex = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(GLfloat[4]));
-       varray_buf_color = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(GLfloat[4]));
-       varray_buf_bcolor = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(GLubyte[4]));
+       size = mesh_maxverts * (sizeof(GLfloat[4]) + sizeof(GLfloat[4]) + sizeof(GLfloat[4]) * backendunits + sizeof(GLubyte[4]));
+       varray_buf_vertex = VID_AllocVertexArrays(gl_backend_mempool, size, gl_mesh_vertex_array_range.integer, gl_mesh_vertex_array_range_readfrequency.value, gl_mesh_vertex_array_range_writefrequency.value, gl_mesh_vertex_array_range_priority.value);
+       varray_buf_color = varray_buf_vertex + 4 * mesh_maxverts;
        for (i = 0;i < backendunits;i++)
-               varray_buf_texcoord[i] = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(GLfloat[4]));
+               varray_buf_texcoord[i] = varray_buf_vertex + (i + 2) * 4 * mesh_maxverts;
        for (;i < MAX_TEXTUREUNITS;i++)
                varray_buf_texcoord[i] = NULL;
+       varray_buf_bcolor = (GLubyte *)(varray_buf_vertex + (backendunits + 2) * 4 * mesh_maxverts);
 
        GL_Backend_AllocElementsArray();
+
+       if (gl_support_var)
+       {
+               CHECKGLERROR
+               qglVertexArrayRangeNV(size, varray_buf_vertex);
+               CHECKGLERROR
+               qglEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
+               CHECKGLERROR
+       }
 }
 
 void GL_Backend_FreeArrays(void)
 {
        int i;
-       Mem_FreePool(&gl_backend_mempool);
 
+       if (gl_support_var)
+       {
+               CHECKGLERROR
+               qglDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
+               CHECKGLERROR
+       }
+
+       if (varray_buf_vertex)
+               VID_FreeVertexArrays(varray_buf_vertex);
        varray_buf_vertex = NULL;
        varray_buf_color = NULL;
        varray_buf_bcolor = NULL;
        for (i = 0;i < MAX_TEXTUREUNITS;i++)
                varray_buf_texcoord[i] = NULL;
 
+       Mem_FreePool(&gl_backend_mempool);
+
        varray_buf_elements = NULL;
 }
 
 static void gl_backend_start(void)
 {
+       GL_Backend_CheckCvars();
+
        Con_Printf("OpenGL Backend started with gl_mesh_maxverts %i\n", gl_mesh_maxverts.integer);
        if (qglDrawRangeElements != NULL)
        {
+               CHECKGLERROR
                qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
+               CHECKGLERROR
                qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
                CHECKGLERROR
                Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
@@ -212,15 +265,6 @@ static void gl_backend_shutdown(void)
        GL_Backend_FreeArrays();
 }
 
-void GL_Backend_CheckCvars(void)
-{
-       // 21760 is (65536 / 3) rounded off to a multiple of 128
-       if (gl_mesh_maxverts.integer < 1024)
-               Cvar_SetValueQuick(&gl_mesh_maxverts, 1024);
-       if (gl_mesh_maxverts.integer > 21760)
-               Cvar_SetValueQuick(&gl_mesh_maxverts, 21760);
-}
-
 void GL_Backend_ResizeArrays(int numvertices)
 {
        Cvar_SetValueQuick(&gl_mesh_maxverts, numvertices);
@@ -255,7 +299,10 @@ void gl_backend_init(void)
        Cvar_RegisterVariable(&gl_mesh_maxverts);
        Cvar_RegisterVariable(&gl_mesh_floatcolors);
        Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
-       GL_Backend_CheckCvars();
+       Cvar_RegisterVariable(&gl_mesh_vertex_array_range);
+       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_readfrequency);
+       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_writefrequency);
+       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_priority);
        R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
 }
 
@@ -530,10 +577,22 @@ void R_Mesh_Start(void)
        CHECKGLERROR
 
        GL_Backend_CheckCvars();
-       if (mesh_maxverts != gl_mesh_maxverts.integer)
+       if (mesh_maxverts != gl_mesh_maxverts.integer
+        || mesh_var != gl_mesh_vertex_array_range.integer
+        || mesh_var_readfrequency != gl_mesh_vertex_array_range_readfrequency.value
+        || mesh_var_writefrequency != gl_mesh_vertex_array_range_writefrequency.value
+        || mesh_var_priority != gl_mesh_vertex_array_range_priority.value)
                GL_Backend_ResizeArrays(gl_mesh_maxverts.integer);
 
        GL_Backend_ResetState();
+
+       if (mesh_var)
+       {
+               CHECKGLERROR
+               qglFlushVertexArrayRangeNV();
+               CHECKGLERROR
+       }
+       varray_offset = 0;
 }
 
 int gl_backend_rebindtextures;
@@ -601,10 +660,7 @@ void R_Mesh_GetSpace(int numverts)
 
        varray_offset = varray_offsetnext;
        if (varray_offset + numverts > mesh_maxverts)
-       {
-               //flush stuff here
                varray_offset = 0;
-       }
        if (numverts > mesh_maxverts)
        {
                BACKENDACTIVECHECK
@@ -613,8 +669,16 @@ void R_Mesh_GetSpace(int numverts)
                varray_offset = 0;
        }
 
+       if (varray_offset == 0 && mesh_var)
+       {
+               CHECKGLERROR
+               qglFlushVertexArrayRangeNV();
+               CHECKGLERROR
+       }
+
        // for debugging
-       //varray_offset = rand() % (mesh_maxverts - numverts);
+       //if (!mesh_var)
+       //      varray_offset = rand() % (mesh_maxverts - numverts);
 
        varray_vertex = varray_buf_vertex + varray_offset * 4;
        varray_color = varray_buf_color + varray_offset * 4;
@@ -677,6 +741,13 @@ void R_Mesh_Finish(void)
 {
        int i;
        BACKENDACTIVECHECK
+       if (mesh_var)
+       {
+               CHECKGLERROR
+               qglFlushVertexArrayRangeNV();
+               CHECKGLERROR
+       }
+       varray_offset = 0;
 
        for (i = backendunits - 1;i >= 0;i--)
        {
index 4ad25be..58068e6 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -354,6 +354,22 @@ extern int gl_support_clamptoedge;
 #define GL_CLAMP_TO_EDGE 0x812F
 #endif
 
+//GL_NV_vertex_array_range
+extern GLvoid *(GLAPIENTRY *qglAllocateMemoryNV)(GLsizei size, GLfloat readFrequency, GLfloat writeFrequency, GLfloat priority);
+extern GLvoid (GLAPIENTRY *qglFreeMemoryNV)(GLvoid *pointer);
+extern GLvoid (GLAPIENTRY *qglVertexArrayRangeNV)(GLsizei length, GLvoid *pointer);
+extern GLvoid (GLAPIENTRY *qglFlushVertexArrayRangeNV)(GLvoid);
+#define GL_VERTEX_ARRAY_RANGE_NV 0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521
+extern int gl_support_var;
+
+//GL_NV_vertex_array_range2
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+extern int gl_support_var2;
+
+
 extern void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
 
 extern void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
diff --git a/vid.h b/vid.h
index 8ea82bb..602238c 100644 (file)
--- a/vid.h
+++ b/vid.h
@@ -100,6 +100,11 @@ void GL_CloseLibrary(void);
 void *GL_GetProcAddress(const char *name);
 int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *disableparm, int silent);
 
+// this attempts to use vendor extensions to allocate faster vertex memory if
+// the fast parameter is true, if unsuccessful it uses Mem_Alloc instead
+void *VID_AllocVertexArrays(mempool_t *pool, int size, int fast, float readfrequency, float writefrequency, float priority);
+void VID_FreeVertexArrays(void *pointer);
+
 void VID_Shared_Init(void);
 
 void GL_Init (void);
index 14c09ca..800b46c 100644 (file)
--- a/vid_glx.c
+++ b/vid_glx.c
@@ -61,7 +61,7 @@ static dllfunction_t getprocaddressfuncs[] =
 
 //GLX_SGI_video_sync
 GLint (GLAPIENTRY *qglXGetVideoSyncSGI)(GLuint *count);
-GLint (GLAPIENTRY *qglXWaitVideoSyncSGI)(int divisor, int remainder, unsigned int *count);
+GLint (GLAPIENTRY *qglXWaitVideoSyncSGI)(GLint divisor, GLint remainder, GLuint *count);
 
 static dllfunction_t videosyncfuncs[] =
 {
@@ -863,3 +863,4 @@ void *GL_GetProcAddress(const char *name)
                p = (void *) dlsym(prjobj, name);
        return p;
 }
+
index 37f2444..8f33726 100644 (file)
@@ -26,6 +26,10 @@ int gl_texturecubemap = false;
 int gl_dot3arb = false;
 // GL_SGIS_texture_edge_clamp
 int gl_support_clamptoedge = false;
+// GL_NV_vertex_array_range
+int gl_support_var = false;
+// GL_NV_vertex_array_range2
+int gl_support_var2 = false;
 
 // LordHavoc: if window is hidden, don't update screen
 int vid_hidden = true;
@@ -98,6 +102,11 @@ void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
 void (GLAPIENTRY *qglLockArraysEXT) (GLint first, GLint count);
 void (GLAPIENTRY *qglUnlockArraysEXT) (void);
 
+//GL_NV_vertex_array_range
+GLvoid *(GLAPIENTRY *qglAllocateMemoryNV)(GLsizei size, GLfloat readFrequency, GLfloat writeFrequency, GLfloat priority);
+GLvoid (GLAPIENTRY *qglFreeMemoryNV)(GLvoid *pointer);
+GLvoid (GLAPIENTRY *qglVertexArrayRangeNV)(GLsizei length, GLvoid *pointer);
+GLvoid (GLAPIENTRY *qglFlushVertexArrayRangeNV)(GLvoid);
 
 // general GL functions
 
@@ -374,6 +383,25 @@ static dllfunction_t texture3dextfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t glxvarfuncs[] =
+{
+       {"glXAllocateMemoryNV", (void **) &qglAllocateMemoryNV},
+       {"glXFreeMemoryNV", (void **) &qglFreeMemoryNV},
+       {"glVertexArrayRangeNV", (void **) &qglVertexArrayRangeNV},
+       {"glFlushVertexArrayRangeNV", (void **) &qglFlushVertexArrayRangeNV},
+       {NULL, NULL}
+};
+
+static dllfunction_t wglvarfuncs[] =
+{
+       {"wglAllocateMemoryNV", (void **) &qglAllocateMemoryNV},
+       {"wglFreeMemoryNV", (void **) &qglFreeMemoryNV},
+       {"glVertexArrayRangeNV", (void **) &qglVertexArrayRangeNV},
+       {"glFlushVertexArrayRangeNV", (void **) &qglFlushVertexArrayRangeNV},
+       {NULL, NULL}
+};
+
+
 void VID_CheckExtensions(void)
 {
        gl_stencil = vid_stencil.integer;
@@ -382,6 +410,8 @@ void VID_CheckExtensions(void)
        gl_supportslockarrays = false;
        gl_textureunits = 1;
        gl_support_clamptoedge = false;
+       gl_support_var = false;
+       gl_support_var2 = false;
 
        if (!GL_CheckExtension("OpenGL 1.1.0", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found\n");
@@ -410,11 +440,50 @@ void VID_CheckExtensions(void)
        gl_supportslockarrays = GL_CheckExtension("GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "-nocva", false);
        gl_support_clamptoedge = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false);
 
+       if (!strcmp(gl_platform, "GLX"))
+               gl_support_var = GL_CheckExtension("GL_NV_vertex_array_range", glxvarfuncs, "-novar", false);
+       else if (!strcmp(gl_platform, "WGL"))
+               gl_support_var = GL_CheckExtension("GL_NV_vertex_array_range", wglvarfuncs, "-novar", false);
+       if (gl_support_var)
+               gl_support_var2 = GL_CheckExtension("GL_NV_vertex_array_range2", NULL, "-novar2", false);
+
        // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
        if (qglDrawRangeElements == NULL)
                qglDrawRangeElements = qglDrawRangeElementsEXT;
 }
 
+int vid_vertexarrays_are_var = false;
+void *VID_AllocVertexArrays(mempool_t *pool, int size, int fast, float readfrequency, float writefrequency, float priority)
+{
+       void *m;
+       vid_vertexarrays_are_var = false;
+       if (fast && qglAllocateMemoryNV)
+       {
+               CHECKGLERROR
+               m = qglAllocateMemoryNV(size, readfrequency, writefrequency, priority);
+               CHECKGLERROR
+               if (m)
+               {
+                       vid_vertexarrays_are_var = true;
+                       return m;
+               }
+       }
+       return Mem_Alloc(pool, size);
+}
+
+void VID_FreeVertexArrays(void *pointer)
+{
+       if (vid_vertexarrays_are_var)
+       {
+               CHECKGLERROR
+               qglFreeMemoryNV(pointer);
+               CHECKGLERROR
+       }
+       else
+               Mem_Free(pointer);
+       vid_vertexarrays_are_var = false;
+}
+
 void Force_CenterView_f (void)
 {
        cl.viewangles[PITCH] = 0;
@@ -717,3 +786,4 @@ void VID_Close(void)
        VID_CloseSystems();
        VID_Shutdown();
 }
+