From 5ad6c0e8577478422c10d7ae79fb61b88ac5ae85 Mon Sep 17 00:00:00 2001
From: cloudwalk <cloudwalk@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sat, 14 Nov 2020 16:26:31 +0000
Subject: [PATCH] gl_draw, model_shared: Refactor vertex adding. Add faster
 codepath that skips hash function for drawing lines. Modest improvement in
 netgraph performance.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@13044 d7cf8633-e32d-0410-b094-e92efae38249
---
 cl_screen.c    | 12 +++----
 clvm_cmds.c    |  2 +-
 draw.h         |  2 +-
 gl_draw.c      | 21 +++++++++---
 model_shared.c | 87 ++++++++++++++++++++++++++++++++------------------
 model_shared.h |  2 ++
 r_stats.c      |  2 +-
 7 files changed, 83 insertions(+), 45 deletions(-)

diff --git a/cl_screen.c b/cl_screen.c
index 186342d1..5b97ccb6 100644
--- a/cl_screen.c
+++ b/cl_screen.c
@@ -285,12 +285,12 @@ static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth,
 		b = g[(j+1)%NETGRAPH_PACKETS];
 		if (a[0] < 0.0f || b[0] > 1.0f || b[0] < a[0])
 			continue;
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[2], graphx + graphwidth * b[0], graphy + graphheight * b[2], 1.0f, 1.0f, 1.0f, 1.0f, 0);
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[1], graphx + graphwidth * b[0], graphy + graphheight * b[1], 1.0f, 0.0f, 0.0f, 1.0f, 0);
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[5], graphx + graphwidth * b[0], graphy + graphheight * b[5], 0.0f, 1.0f, 0.0f, 1.0f, 0);
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[4], graphx + graphwidth * b[0], graphy + graphheight * b[4], 1.0f, 1.0f, 1.0f, 1.0f, 0);
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[3], graphx + graphwidth * b[0], graphy + graphheight * b[3], 1.0f, 0.5f, 0.0f, 1.0f, 0);
-		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[6], graphx + graphwidth * b[0], graphy + graphheight * b[6], 0.0f, 0.0f, 1.0f, 1.0f, 0);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[2], graphx + graphwidth * b[0], graphy + graphheight * b[2], 1.0f, 1.0f, 1.0f, 1.0f, 0, true);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[1], graphx + graphwidth * b[0], graphy + graphheight * b[1], 1.0f, 0.0f, 0.0f, 1.0f, 0, true);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[5], graphx + graphwidth * b[0], graphy + graphheight * b[5], 0.0f, 1.0f, 0.0f, 1.0f, 0, true);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[4], graphx + graphwidth * b[0], graphy + graphheight * b[4], 1.0f, 1.0f, 1.0f, 1.0f, 0, true);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[3], graphx + graphwidth * b[0], graphy + graphheight * b[3], 1.0f, 0.5f, 0.0f, 1.0f, 0, true);
+		DrawQ_Line(1, graphx + graphwidth * a[0], graphy + graphheight * a[6], graphx + graphwidth * b[0], graphy + graphheight * b[6], 0.0f, 0.0f, 1.0f, 1.0f, 0, true);
 	}
 	x = graphx;
 	y = graphy + graphheight;
diff --git a/clvm_cmds.c b/clvm_cmds.c
index adf20144..7f2dffbe 100644
--- a/clvm_cmds.c
+++ b/clvm_cmds.c
@@ -1215,7 +1215,7 @@ void VM_drawline (prvm_prog_t *prog)
 	rgb		= PRVM_G_VECTOR(OFS_PARM3);
 	alpha	= PRVM_G_FLOAT(OFS_PARM4);
 	flags	= (int)PRVM_G_FLOAT(OFS_PARM5);
-	DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags);
+	DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags, false);
 }
 
 /*
diff --git a/draw.h b/draw.h
index 381dd35e..e06f19aa 100644
--- a/draw.h
+++ b/draw.h
@@ -174,7 +174,7 @@ void DrawQ_SetClipArea(float x, float y, float width, float height);
 // reset the clipping area
 void DrawQ_ResetClipArea(void);
 // draw a line
-void DrawQ_Line(float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags);
+void DrawQ_Line(float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags, qbool fast);
 
 const char *Draw_GetPicName(cachepic_t *pic);
 int Draw_GetPicWidth(cachepic_t *pic);
diff --git a/gl_draw.c b/gl_draw.c
index 2211f261..3de01e19 100644
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -1404,7 +1404,7 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
 	Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
 }
 
-void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
+void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags, qbool fast)
 {
 	model_t *mod = CL_Mesh_UI();
 	msurface_t *surf;
@@ -1422,10 +1422,21 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
 		offsety = 0;
 	}
 	surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
-	e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
-	e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
-	e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
-	e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+	if (fast)
+	{
+		Mod_Mesh_CheckResize_Vertex(mod, surf);
+		e0 = Mod_Mesh_AddVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e1 = Mod_Mesh_AddVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e2 = Mod_Mesh_AddVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e3 = Mod_Mesh_AddVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+	}
+	else
+	{
+		e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+		e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
+	}
 	Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
 	Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
 }
diff --git a/model_shared.c b/model_shared.c
index 5c69dd23..55b4673e 100644
--- a/model_shared.c
+++ b/model_shared.c
@@ -4506,10 +4506,31 @@ msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithpre
 	return surf;
 }
 
-int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+static void Mod_Mesh_RebuildHashTable(model_t *mod, msurface_t *surf)
 {
 	int hashindex, h, vnum, mask;
 	surfmesh_t *mesh = &mod->surfmesh;
+
+	// rebuild the hash table
+	mesh->num_vertexhashsize = 4 * mesh->max_vertices;
+	mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
+	mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+	memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+	mask = mod->surfmesh.num_vertexhashsize - 1;
+	// no need to hash the vertices for the entire model, the latest surface will suffice.
+	for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
+	{
+		// this uses prime numbers intentionally for computing the hash
+		hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask;
+		for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
+			; // just iterate until we find the terminator
+		mesh->data_vertexhash[h] = vnum;
+	}
+}
+
+void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf)
+{
+	surfmesh_t *mesh = &mod->surfmesh;
 	if (mesh->max_vertices == mesh->num_vertices)
 	{
 		mesh->max_vertices = max(mesh->num_vertices * 2, 256);
@@ -4520,36 +4541,15 @@ int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, fl
 		mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
 		mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
 		mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
-		// rebuild the hash table
-		mesh->num_vertexhashsize = 4 * mesh->max_vertices;
-		mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
-		mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
-		memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
-		mask = mod->surfmesh.num_vertexhashsize - 1;
-		// no need to hash the vertices for the entire model, the latest surface will suffice.
-		for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
-		{
-			// this uses prime numbers intentionally for computing the hash
-			hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask;
-			for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
-				; // just iterate until we find the terminator
-			mesh->data_vertexhash[h] = vnum;
-		}
-	}
-	mask = mod->surfmesh.num_vertexhashsize - 1;
-	// this uses prime numbers intentionally for computing the hash
-	hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
-	// when possible find an identical vertex within the same surface and return it
-	for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
-	{
-		if (vnum >= surf->num_firstvertex
-		 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
-		 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
-		 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
-		 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
-		 && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a)
-			return vnum;
+		Mod_Mesh_RebuildHashTable(mod, surf);
 	}
+}
+
+int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+{
+	int vnum;
+	surfmesh_t *mesh = &mod->surfmesh;
+
 	// add the new vertex
 	vnum = mesh->num_vertices++;
 	if (surf->num_vertices > 0)
@@ -4567,7 +4567,6 @@ int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, fl
 		VectorSet(surf->maxs, x, y, z);
 	}
 	surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
-	mesh->data_vertexhash[h] = vnum;
 	mesh->data_vertex3f[vnum * 3 + 0] = x;
 	mesh->data_vertex3f[vnum * 3 + 1] = y;
 	mesh->data_vertex3f[vnum * 3 + 2] = z;
@@ -4585,6 +4584,32 @@ int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, fl
 	return vnum;
 }
 
+int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+{
+	int hashindex, h, vnum, mask;
+	surfmesh_t *mesh = &mod->surfmesh;
+
+	Mod_Mesh_CheckResize_Vertex(mod, surf);
+
+	mask = mod->surfmesh.num_vertexhashsize - 1;
+	// this uses prime numbers intentionally for computing the hash
+	hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
+	// when possible find an identical vertex within the same surface and return it
+	for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
+	{
+		if (vnum >= surf->num_firstvertex
+		 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
+		 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
+		 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
+		 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
+		 && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a)
+			return vnum;
+	}
+	vnum = Mod_Mesh_AddVertex(mod, surf, x, y, z, nx, ny, nz, s, t, u, v, r, g, b, a);
+	mesh->data_vertexhash[h] = vnum;
+	return vnum;
+}
+
 void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2)
 {
 	surfmesh_t *mesh = &mod->surfmesh;
diff --git a/model_shared.h b/model_shared.h
index 0e477789..6b0530a8 100644
--- a/model_shared.h
+++ b/model_shared.h
@@ -698,6 +698,8 @@ void Mod_Mesh_Destroy(model_t *mod);
 void Mod_Mesh_Reset(model_t *mod);
 texture_t *Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags);
 msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithprevioussurface);
+void Mod_Mesh_CheckResize_Vertex(model_t *mod, msurface_t *surf);
+int Mod_Mesh_AddVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a);
 int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a);
 void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2);
 void Mod_Mesh_Validate(model_t *mod);
diff --git a/r_stats.c b/r_stats.c
index 6dfc7938..edb4625f 100644
--- a/r_stats.c
+++ b/r_stats.c
@@ -504,7 +504,7 @@ void R_TimeReport_EndFrame(void)
 					i++;
 					x2 = max(x, x + width - sum * scalex);
 					y2 = y + height - (data[index] - range_min) * scaley;
-					DrawQ_Line(1, x1, y1, x2, y2, r_speeds_graph_colors[color][0], r_speeds_graph_colors[color][1], r_speeds_graph_colors[color][2], r_speeds_graph_colors[color][3], 0);
+					DrawQ_Line(1, x1, y1, x2, y2, r_speeds_graph_colors[color][0], r_speeds_graph_colors[color][1], r_speeds_graph_colors[color][2], r_speeds_graph_colors[color][3], 0, true);
 				}
 			}
 		}
-- 
2.39.5