]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Batch multidraws into glMultiDrawElements uis/glmultidraw
authoruis <uis9936@gmail.com>
Sat, 30 Dec 2023 22:17:00 +0000 (01:17 +0300)
committeruis <uis9936@gmail.com>
Sat, 30 Dec 2023 22:17:00 +0000 (01:17 +0300)
gl_backend.c
gl_rmain.c
glquake.h
vid_shared.c

index 32a6ee7d18051968669747a72c617e30c72126b7..e2b55543d0fae96b50a6dff83af7587ebcd492b0 100644 (file)
@@ -933,7 +933,7 @@ static void GL_BindVBO(int bufferobject)
        }
 }
 
-static void GL_BindEBO(int bufferobject)
+void GL_BindEBO(int bufferobject)
 {
        if (gl_state.elementbufferobject != bufferobject)
        {
index 28806317dba62ddf78b7cdda947a11ea96a0baa3..8e62167e13cdc00b30f5111c685231f71e5ab38f 100644 (file)
@@ -8472,6 +8472,9 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        }
 }
 
+static void **drawbatch_buffer = NULL;
+static size_t drawbatch_buffer_size = 0;
+extern void GL_BindEBO(int bufferobject);
 void RSurf_DrawBatch(void)
 {
        // sometimes a zero triangle surface (usually a degenerate patch) makes it
@@ -8507,11 +8510,36 @@ void RSurf_DrawBatch(void)
        if (rsurface.batchmultidraw)
        {
                // issue multiple draws rather than copying index data
-               int numsurfaces = rsurface.batchmultidrawnumsurfaces;
-               const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
-               int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
-               for (i = 0;i < numsurfaces;)
+               const msurface_t **surfacelist;
+               int numsurfaces;
+               int drawcount;
+               void **firstoffset;
+               GLsizei *indcount;
+               int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle, idraw;
+               surfacelist = rsurface.batchmultidrawsurfacelist;
+               numsurfaces = rsurface.batchmultidrawnumsurfaces;
+               // count entries in batch
+               drawcount = 1;
+               for (k = 0, j = 1; j < numsurfaces; k = j, j++)
+                       if (surfacelist[j] != surfacelist[k] + 1)
+                               drawcount++;
+               {
+                       size_t size;
+                       size = drawcount * (sizeof(void*) + sizeof(GLsizei));
+                       if(size > drawbatch_buffer_size) {
+                               Mem_Free(drawbatch_buffer);
+                               drawbatch_buffer = NULL;
+                       }
+                       if(!drawbatch_buffer) {
+                               drawbatch_buffer_size = size < 128 ? 128 : size;
+                               drawbatch_buffer = (void**)Mem_Alloc(r_main_mempool, drawbatch_buffer_size * (sizeof(void*) + sizeof(GLsizei)));
+                       }
+                       firstoffset = drawbatch_buffer;
+                       indcount = (GLsizei*)(drawbatch_buffer + drawcount);
+               }
+               for (i = 0, idraw = 0;i < numsurfaces; idraw++)
                {
+                       assert(idraw < drawcount);
                        // combine consecutive surfaces as one draw
                        for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
                                if (surfacelist[j] != surfacelist[k] + 1)
@@ -8520,9 +8548,36 @@ void RSurf_DrawBatch(void)
                        endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
                        firsttriangle = surfacelist[i]->num_firsttriangle;
                        endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
-                       R_Mesh_Draw(firstvertex, endvertex - firstvertex, firsttriangle, endtriangle - firsttriangle, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
+                       if(rsurface.batchelement3s_indexbuffer) {
+                               firstoffset[idraw] = (void*)(rsurface.batchelement3s_bufferoffset + (firsttriangle * 3 * sizeof(GLushort)));
+                               indcount[idraw] = (endtriangle - firsttriangle) * 3;
+                               r_refdef.stats[r_stat_draws]++;
+                               r_refdef.stats[r_stat_draws_vertices] += endvertex - firstvertex;
+                               r_refdef.stats[r_stat_draws_elements] += endtriangle - firsttriangle;
+                       } else if (rsurface.batchelement3i_indexbuffer) {
+                               firstoffset[idraw] = (void*)(rsurface.batchelement3i_bufferoffset + (firsttriangle * 3 * sizeof(GLuint)));
+                               indcount[idraw] = (endtriangle - firsttriangle) * 3;
+                               r_refdef.stats[r_stat_draws]++;
+                               r_refdef.stats[r_stat_draws_vertices] += endvertex - firstvertex;
+                               r_refdef.stats[r_stat_draws_elements] += endtriangle - firsttriangle;
+                       } else {
+                               // fallback for dynamic surface and glDrawArray
+                               R_Mesh_Draw(firstvertex, endvertex - firstvertex, firsttriangle, endtriangle - firsttriangle, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
+                       }
                        i = j;
                }
+
+               if (rsurface.batchelement3s_indexbuffer) {
+                       CHECKGLERROR
+                       GL_BindEBO(rsurface.batchelement3s_indexbuffer->bufferobject);
+                       qglMultiDrawElements(GL_TRIANGLES, indcount, GL_UNSIGNED_SHORT, firstoffset, drawcount);
+                       CHECKGLERROR
+               } else if (rsurface.batchelement3i_indexbuffer) {
+                       CHECKGLERROR
+                       GL_BindEBO(rsurface.batchelement3i_indexbuffer->bufferobject);
+                       qglMultiDrawElements(GL_TRIANGLES, indcount, GL_UNSIGNED_INT, firstoffset, drawcount);
+                       CHECKGLERROR
+               }
        }
        else
        {
index 46efbf0721fe6ac23334c0a201fe1f9502d918b4..2ad84f6e059a16c99b73cb0a922febb8f9d3a0de 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -671,6 +671,7 @@ extern void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count)
 extern void (GLAPIENTRY *qglDrawBuffer)(GLenum mode);
 extern void (GLAPIENTRY *qglDrawBuffers)(GLsizei n, const GLenum *bufs);
 extern void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+extern void (GLAPIENTRY *qglMultiDrawElements)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *indices, GLsizei drawcount);
 extern void (GLAPIENTRY *qglEnable)(GLenum cap);
 extern void (GLAPIENTRY *qglEnableVertexAttribArray)(GLuint index);
 extern void (GLAPIENTRY *qglEndQuery)(GLenum target);
@@ -851,6 +852,7 @@ extern void (GLAPIENTRY *qglViewport)(GLint x, GLint y, GLsizei width, GLsizei h
 #define qglDrawBuffer glDrawBuffer
 #define qglDrawBuffers glDrawBuffers
 #define qglDrawElements glDrawElements
+#define qglMultiDrawElements glMultiDrawElements
 #define qglEnable glEnable
 #define qglEnableVertexAttribArray glEnableVertexAttribArray
 #define qglEndQuery glEndQuery
index ab55661a6eff572af83f574e1c2f9f8be59b552a..3c988c3eab205b672ca578deddaba2077b258b0b 100644 (file)
@@ -278,6 +278,7 @@ void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count);
 void (GLAPIENTRY *qglDrawBuffer)(GLenum mode);
 void (GLAPIENTRY *qglDrawBuffers)(GLsizei n, const GLenum *bufs);
 void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void (GLAPIENTRY *qglMultiDrawElements)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *indices, GLsizei drawcount);
 void (GLAPIENTRY *qglEnable)(GLenum cap);
 void (GLAPIENTRY *qglEnableVertexAttribArray)(GLuint index);
 void (GLAPIENTRY *qglEndQuery)(GLenum target);
@@ -473,6 +474,7 @@ static glfunction_t openglfuncs[] =
        {"core", "glDrawBuffer", (void **) &qglDrawBuffer},
        {"core", "glDrawBuffers", (void **) &qglDrawBuffers},
        {"core", "glDrawElements", (void **) &qglDrawElements},
+       {"core", "glMultiDrawElements", (void **) &qglMultiDrawElements},
        {"core", "glEnable", (void **) &qglEnable},
        {"core", "glEnableVertexAttribArray", (void **) &qglEnableVertexAttribArray},
        {"core", "glEndQuery", (void **) &qglEndQuery},