]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_backend.c
cleaned up glDrawRangeElements limit checking a bit (now done in gl_backend.c)
[xonotic/darkplaces.git] / gl_backend.c
index 1df56bdfd33f67c018d6c59d3734d23b21ecfc99..4c1cd30d7722ed41281e7ee53ed31144d6c045d1 100644 (file)
@@ -1,9 +1,7 @@
 
 #include "quakedef.h"
 
-//cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "21760"};
 cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "1024"};
-//cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "1024"};
 cvar_t gl_mesh_batchtriangles = {0, "gl_mesh_batchtriangles", "0"};
 cvar_t gl_mesh_transtriangles = {0, "gl_mesh_transtriangles", "16384"};
 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "0"};
@@ -13,6 +11,12 @@ cvar_t r_render = {0, "r_render", "1"};
 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
 
+// this is used to increase gl_mesh_maxtriangles automatically if a mesh was
+// too large for the buffers in the previous frame
+int overflowedverts = 0;
+// increase transtriangles automatically too
+int overflowedtransverts = 0;
+
 int gl_maxdrawrangeelementsvertices;
 int gl_maxdrawrangeelementsindices;
 
@@ -166,6 +170,14 @@ static void gl_backend_start(void)
 {
        int i;
 
+       qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
+       qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
+
+       Con_Printf("OpenGL Backend started with gl_mesh_maxtriangles %i, gl_mesh_transtriangles %i", gl_mesh_maxtriangles.integer, gl_mesh_transtriangles.integer);
+       if (qglDrawRangeElements != NULL)
+               Con_Printf(", with glDrawRangeElements (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
+       Con_Printf("\n");
+
        max_verts = max_meshs * 3;
        max_transverts = max_transmeshs * 3;
 
@@ -213,6 +225,8 @@ static void gl_backend_start(void)
 
 static void gl_backend_shutdown(void)
 {
+       Con_Printf("OpenGL Backend shutting down\n");
+
        if (resizingbuffers)
                Mem_EmptyPool(gl_backend_mempool);
        else
@@ -224,22 +238,33 @@ static void gl_backend_shutdown(void)
 
 static void gl_backend_bufferchanges(int init)
 {
-       if (gl_mesh_drawmode.integer == 3)
+       if (overflowedverts > gl_mesh_maxtriangles.integer * 3)
+               Cvar_SetValueQuick(&gl_mesh_maxtriangles, (int) ((overflowedverts + 2) / 3));
+       overflowedverts = 0;
+
+       if (overflowedtransverts > gl_mesh_transtriangles.integer * 3)
+               Cvar_SetValueQuick(&gl_mesh_transtriangles, (int) ((overflowedtransverts + 2) / 3));
+       overflowedtransverts = 0;
+
+       if (gl_mesh_drawmode.integer < 0)
+               Cvar_SetValueQuick(&gl_mesh_drawmode, 0);
+       if (gl_mesh_drawmode.integer > 3)
+               Cvar_SetValueQuick(&gl_mesh_drawmode, 3);
+
+       if (gl_mesh_drawmode.integer >= 3 && qglDrawRangeElements == NULL)
        {
-               if (gl_mesh_maxtriangles.integer * 3 > gl_maxdrawrangeelementsindices)
-                       Cvar_SetValueQuick(&gl_mesh_maxtriangles, (int) (gl_maxdrawrangeelementsindices / 3));
-               if (gl_mesh_maxtriangles.integer * 3 > gl_maxdrawrangeelementsvertices)
-                       Cvar_SetValueQuick(&gl_mesh_maxtriangles, (int) (gl_maxdrawrangeelementsvertices / 3));
+               // change drawmode 3 to 2 if 3 won't work at all
+               Cvar_SetValueQuick(&gl_mesh_drawmode, 2);
        }
 
        // 21760 is (65536 / 3) rounded off to a multiple of 128
-       if (gl_mesh_maxtriangles.integer < 256)
-               Cvar_SetValueQuick(&gl_mesh_maxtriangles, 256);
+       if (gl_mesh_maxtriangles.integer < 1024)
+               Cvar_SetValueQuick(&gl_mesh_maxtriangles, 1024);
        if (gl_mesh_maxtriangles.integer > 21760)
                Cvar_SetValueQuick(&gl_mesh_maxtriangles, 21760);
 
-       if (gl_mesh_transtriangles.integer < 256)
-               Cvar_SetValueQuick(&gl_mesh_transtriangles, 256);
+       if (gl_mesh_transtriangles.integer < 1024)
+               Cvar_SetValueQuick(&gl_mesh_transtriangles, 1024);
        if (gl_mesh_transtriangles.integer > 65536)
                Cvar_SetValueQuick(&gl_mesh_transtriangles, 65536);
 
@@ -300,7 +325,7 @@ int arraylocked = false;
 
 void GL_LockArray(int first, int count)
 {
-       if (!arraylocked && gl_supportslockarrays && gl_lockarrays.integer && gl_mesh_drawmode.integer != 0)
+       if (!arraylocked && gl_supportslockarrays && gl_lockarrays.integer && gl_mesh_drawmode.integer > 0)
        {
                qglLockArraysEXT(first, count);
                CHECKGLERROR
@@ -318,8 +343,6 @@ void GL_UnlockArray(void)
        }
 }
 
-//static float gldepthmin, gldepthmax;
-
 /*
 =============
 GL_SetupFrame
@@ -336,13 +359,8 @@ static void GL_SetupFrame (void)
        if (!r_render.integer)
                return;
 
-//     qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: moved to SCR_UpdateScreen
-//     gldepthmin = 0;
-//     gldepthmax = 1;
        qglDepthFunc (GL_LEQUAL);CHECKGLERROR
 
-//     qglDepthRange (gldepthmin, gldepthmax);CHECKGLERROR
-
        // set up viewpoint
        qglMatrixMode(GL_PROJECTION);CHECKGLERROR
        qglLoadIdentity ();CHECKGLERROR
@@ -366,8 +384,6 @@ static void GL_SetupFrame (void)
        // set view pyramid
        qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
 
-//     qglCullFace(GL_FRONT);CHECKGLERROR
-
        qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
        qglLoadIdentity ();CHECKGLERROR
 
@@ -380,24 +396,6 @@ static void GL_SetupFrame (void)
        qglRotatef (-r_refdef.viewangles[1],  0, 0, 1);CHECKGLERROR
        // camera location
        qglTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);CHECKGLERROR
-
-//     qglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
-
-       //
-       // set drawing parms
-       //
-//     if (gl_cull.integer)
-//     {
-//             qglEnable(GL_CULL_FACE);CHECKGLERROR
-//     }
-//     else
-//     {
-//             qglDisable(GL_CULL_FACE);CHECKGLERROR
-//     }
-
-//     qglEnable(GL_BLEND);CHECKGLERROR
-//     qglEnable(GL_DEPTH_TEST);CHECKGLERROR
-//     qglDepthMask(1);CHECKGLERROR
 }
 
 static int mesh_blendfunc1;
@@ -451,7 +449,7 @@ void GL_SetupTextureState(void)
                        {
                                qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                        }
-                       if (gl_mesh_drawmode.integer != 0)
+                       if (gl_mesh_drawmode.integer > 0)
                        {
                                qglClientActiveTexture(GL_TEXTURE0_ARB + (mesh_clientunit = i));CHECKGLERROR
                                qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[i]);CHECKGLERROR
@@ -478,7 +476,7 @@ void GL_SetupTextureState(void)
                {
                        qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                }
-               if (gl_mesh_drawmode.integer != 0)
+               if (gl_mesh_drawmode.integer > 0)
                {
                        qglTexCoordPointer(2, GL_FLOAT, sizeof(buf_texcoord_t), buf_texcoord[0]);CHECKGLERROR
                        if (mesh_texture[0])
@@ -548,7 +546,7 @@ void R_Mesh_Start(void)
        qglDepthMask(mesh_depthmask);CHECKGLERROR
 
        usedarrays = false;
-       if (gl_mesh_drawmode.integer != 0)
+       if (gl_mesh_drawmode.integer > 0)
        {
                usedarrays = true;
                qglVertexPointer(3, GL_FLOAT, sizeof(buf_vertex_t), &buf_vertex[0].v[0]);CHECKGLERROR
@@ -592,8 +590,12 @@ void GL_UpdateFarclip(void)
 
 void GL_ConvertColorsFloatToByte(void)
 {
-       int i, k, total, *icolor;
-       float *fcolor;
+       int i, k, total;
+       // LordHavoc: to avoid problems with aliasing (treating memory as two
+       // different types - exactly what this is doing), these must be volatile
+       // (or a union)
+       volatile int *icolor;
+       volatile float *fcolor;
        qbyte *bcolor;
 
        total = currentvertex * 4;
@@ -736,20 +738,17 @@ void GL_MeshState(buf_mesh_t *mesh)
 void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *index)
 {
        unsigned int i, j, in;
-       if (gl_mesh_drawmode.integer == 3 && qglDrawRangeElements == NULL)
-               Cvar_SetValueQuick(&gl_mesh_drawmode, 2);
-
-       if (gl_mesh_drawmode.integer == 3)
+       if (gl_mesh_drawmode.integer >= 3/* && (endvert - firstvert) <= gl_maxdrawrangeelementsvertices && (indexcount) <= gl_maxdrawrangeelementsindices*/)
        {
                // GL 1.2 or GL 1.1 with extension
                qglDrawRangeElements(GL_TRIANGLES, firstvert, endvert, indexcount, GL_UNSIGNED_INT, index);
        }
-       else if (gl_mesh_drawmode.integer == 2)
+       else if (gl_mesh_drawmode.integer >= 2)
        {
                // GL 1.1
                qglDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);
        }
-       else if (gl_mesh_drawmode.integer == 1)
+       else if (gl_mesh_drawmode.integer >= 1)
        {
                // GL 1.1
                // feed it manually using glArrayElement
@@ -762,8 +761,6 @@ void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *in
        {
                // GL 1.1 but not using vertex arrays - 3dfx glquake minigl driver
                // feed it manually
-               if (gl_mesh_drawmode.integer != 0)
-                       Cvar_SetValueQuick(&gl_mesh_drawmode, 0);
                qglBegin(GL_TRIANGLES);
                if (r_multitexture.integer)
                {
@@ -791,19 +788,6 @@ void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *in
                }
                qglEnd();
        }
-       /*
-       if (qglDrawRangeElements)
-               qglDrawRangeElements(GL_TRIANGLES, firstvert, endvert, indexcount, index);
-       else
-       {
-       }
-       #ifdef WIN32
-       // FIXME: dynamic link to GL so we can get DrawRangeElements on WIN32
-       qglDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);CHECKGLERROR
-       #else
-       qglDrawRangeElements(GL_TRIANGLES, firstvert, firstvert + mesh->verts, indexcount, GL_UNSIGNED_INT, index);CHECKGLERROR
-       #endif
-       */
 }
 
 // renders mesh buffers, called to flush buffers when full
@@ -822,15 +806,22 @@ void R_Mesh_Render(void)
        if (!currentmesh)
                return;
 
+       if (!r_render.integer)
+       {
+               currentmesh = 0;
+               currenttriangle = 0;
+               currentvertex = 0;
+               return;
+       }
+
        CHECKGLERROR
 
        GL_UpdateFarclip();
 
-       if (!gl_mesh_floatcolors.integer || gl_mesh_drawmode.integer == 0)
+       // drawmode 0 always uses byte colors
+       if (!gl_mesh_floatcolors.integer || gl_mesh_drawmode.integer <= 0)
                GL_ConvertColorsFloatToByte();
 
-       // lock the arrays now that they will have no further modifications
-       //GL_LockArray(0, currentvertex);CHECKGLERROR
        if (gl_backend_rebindtextures)
        {
                gl_backend_rebindtextures = false;
@@ -1092,22 +1083,28 @@ void R_Mesh_Draw(const rmeshinfo_t *m)
                        Host_Error("R_Mesh_Draw: invalid index (%i of %i verts)\n", m->index, m->numverts);
 #endif
 
+       // LordHavoc: removed this error condition because with floatcolors 0,
+       // the 3DFX driver works with very large meshs
        // FIXME: we can work around this by falling back on non-array renderer if buffers are too big
-       if (m->numtriangles > 1024 || m->numverts > 3072)
-       {
-               Con_Printf("R_Mesh_Draw: mesh too big for 3DFX drivers, rejected\n");
-               return;
-       }
+       //if (m->numtriangles > 1024 || m->numverts > 3072)
+       //{
+       //      Con_Printf("R_Mesh_Draw: mesh too big for 3DFX drivers, rejected\n");
+       //      return;
+       //}
+
+       i = max(m->numtriangles * 3, m->numverts);
+       if (overflowedverts < i)
+               overflowedverts = i;
 
        if (m->numtriangles > max_meshs || m->numverts > max_verts)
        {
-               Con_Printf("R_Mesh_Draw: mesh too big for current gl_mesh_maxtriangles setting, rejected\n");
+               Con_Printf("R_Mesh_Draw: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
                return;
        }
 
-
        if (m->transparent)
        {
+               overflowedtransverts += max(m->numtriangles * 3, m->numverts);
                if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
                {
                        if (!transranout)
@@ -1249,10 +1246,9 @@ void R_Mesh_Draw(const rmeshinfo_t *m)
                else
                        memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
        }
-       #if 0
-       for (;j < backendunits;j++)
-               memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
-       #endif
+
+       if (currenttriangle >= max_batch)
+               R_Mesh_Render();
 }
 
 void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
@@ -1289,22 +1285,28 @@ void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
                        return;
        }
 
+       // LordHavoc: removed this error condition because with floatcolors 0,
+       // the 3DFX driver works with very large meshs
        // FIXME: we can work around this by falling back on non-array renderer if buffers are too big
-       if (m->numtriangles > 1024 || m->numverts > 3072)
-       {
-               Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for 3DFX drivers, rejected\n");
-               return;
-       }
+       //if (m->numtriangles > 1024 || m->numverts > 3072)
+       //{
+       //      Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for 3DFX drivers, rejected\n");
+       //      return;
+       //}
+
+       i = max(m->numtriangles * 3, m->numverts);
+       if (overflowedverts < i)
+               overflowedverts = i;
 
        if (m->numtriangles > max_meshs || m->numverts > max_verts)
        {
-               Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for current gl_mesh_maxtriangles setting, rejected\n");
+               Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
                return;
        }
 
-
        if (m->transparent)
        {
+               overflowedtransverts += max(m->numtriangles * 3, m->numverts);
                if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
                {
                        if (!transranout)
@@ -1408,10 +1410,6 @@ void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
        memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
        for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
                memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
-       #if 0
-       for (;j < backendunits;j++)
-               memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
-       #endif
 
        memcpy(fcolor, m->color, m->numverts * sizeof(buf_fcolor_t));
 
@@ -1425,6 +1423,9 @@ void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
                        fcolor[i].c[2] *= scaler;
                }
        }
+
+       if (currenttriangle >= max_batch)
+               R_Mesh_Render();
 }
 
 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
@@ -1443,22 +1444,28 @@ int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m)
         || !m->numverts)
                Host_Error("R_Mesh_Draw: no triangles or verts\n");
 
+       // LordHavoc: removed this error condition because with floatcolors 0,
+       // the 3DFX driver works with very large meshs
        // FIXME: we can work around this by falling back on non-array renderer if buffers are too big
-       if (m->numtriangles > 1024 || m->numverts > 3072)
-       {
-               Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for 3DFX drivers, rejected\n");
-               return false;
-       }
+       //if (m->numtriangles > 1024 || m->numverts > 3072)
+       //{
+       //      Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for 3DFX drivers, rejected\n");
+       //      return false;
+       //}
+
+       i = max(m->numtriangles * 3, m->numverts);
+       if (overflowedverts < i)
+               overflowedverts = i;
 
        if (m->numtriangles > max_meshs || m->numverts > max_verts)
        {
-               Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for current gl_mesh_maxtriangles setting, rejected\n");
+               Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
                return false;
        }
 
-
        if (m->transparent)
        {
+               overflowedtransverts += max(m->numtriangles * 3, m->numverts);
                if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
                {
                        if (!transranout)
@@ -1634,9 +1641,6 @@ text to the screen.
 */
 void SCR_UpdateScreen (void)
 {
-       //Mem_CheckSentinelsGlobal();
-       //R_TimeReport("memtest");
-
        VID_Finish ();
 
        R_TimeReport("finish");
@@ -1667,3 +1671,4 @@ void SCR_UpdateScreen (void)
        // (this doesn't wait for the commands themselves to complete)
        qglFlush();
 }
+