From 8dc9a3170753133196f2881dac3447d11fd4af77 Mon Sep 17 00:00:00 2001 From: uis Date: Sun, 31 Dec 2023 01:17:00 +0300 Subject: [PATCH] Batch multidraws into glMultiDrawElements --- gl_backend.c | 2 +- gl_rmain.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++---- glquake.h | 2 ++ vid_shared.c | 2 ++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/gl_backend.c b/gl_backend.c index 32a6ee7d..e2b55543 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -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) { diff --git a/gl_rmain.c b/gl_rmain.c index 28806317..8e62167e 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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 { diff --git a/glquake.h b/glquake.h index 46efbf07..2ad84f6e 100644 --- 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 diff --git a/vid_shared.c b/vid_shared.c index ab55661a..3c988c3e 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -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}, -- 2.39.2