Skip to content

Commit a78378e

Browse files
committed
Move some surface optimisation to GeometryOptimiser
Also use tempMemory with only the renderable surfaces, to avoid looping over everything and to remove useless checks for `surfaceType`.
1 parent d33d5ca commit a78378e

File tree

4 files changed

+205
-325
lines changed

4 files changed

+205
-325
lines changed

src/engine/renderer/GeometryOptimiser.cpp

Lines changed: 132 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,19 @@ static int LeafSurfaceCompare( const void* a, const void* b ) {
7373
return 0;
7474
}
7575

76-
bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
76+
static void CoreResetSurfaceViewCounts( bspSurface_t** rendererSurfaces, int numSurfaces ) {
77+
for ( int i = 0; i < numSurfaces; i++ ) {
78+
bspSurface_t* surface = rendererSurfaces[i];
79+
80+
surface->viewCount = -1;
81+
surface->lightCount = -1;
82+
surface->interactionBits = 0;
83+
}
84+
}
85+
86+
void OptimiseMapGeometryCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces ) {
87+
CoreResetSurfaceViewCounts( rendererSurfaces, numSurfaces );
88+
7789
// mark matching surfaces
7890
for ( int i = 0; i < world->numnodes - world->numDecisionNodes; i++ ) {
7991
bspNode_t *leaf = world->nodes + world->numDecisionNodes + i;
@@ -85,17 +97,12 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
8597
continue;
8698
}
8799

88-
if ( *surf1->data != surfaceType_t::SF_GRID && *surf1->data != surfaceType_t::SF_TRIANGLES
89-
&& *surf1->data != surfaceType_t::SF_FACE ) {
100+
if ( !surf1->renderable ) {
90101
continue;
91102
}
92103

93104
shader_t* shader1 = surf1->shader;
94105

95-
if ( shader1->isPortal || shader1->autoSpriteMode != 0 ) {
96-
continue;
97-
}
98-
99106
int fogIndex1 = surf1->fogIndex;
100107
int lightMapNum1 = surf1->lightmapNum;
101108
surf1->viewCount = surf1 - world->surfaces;
@@ -110,8 +117,7 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
110117
continue;
111118
}
112119

113-
if ( *surf2->data != surfaceType_t::SF_GRID && *surf2->data != surfaceType_t::SF_TRIANGLES
114-
&& *surf2->data != surfaceType_t::SF_FACE ) {
120+
if ( !surf2->renderable ) {
115121
continue;
116122
}
117123

@@ -138,31 +144,122 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
138144
}
139145
}
140146

141-
bspSurface_t** coreSurfaces = ( bspSurface_t** ) ri.Hunk_AllocateTempMemory( sizeof( bspSurface_t* ) * numSurfaces );
147+
qsort( rendererSurfaces, numSurfaces, sizeof( bspSurface_t* ), LeafSurfaceCompare );
148+
}
149+
150+
static void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float* radius ) {
151+
vec3_t temp;
142152

143-
numSurfaces = 0;
144-
for ( int k = 0; k < world->numSurfaces; k++ ) {
145-
bspSurface_t* surface = &world->surfaces[k];
153+
VectorAdd( mins, maxs, origin );
154+
VectorScale( origin, 0.5, origin );
155+
VectorSubtract( maxs, origin, temp );
156+
*radius = VectorLength( temp );
157+
}
158+
159+
void MergeLeafSurfacesCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces ) {
160+
if ( !r_mergeLeafSurfaces->integer ) {
161+
return;
162+
}
163+
164+
// count merged/unmerged surfaces
165+
int numUnmergedSurfaces = 0;
166+
int numMergedSurfaces = 0;
167+
int oldViewCount = -2;
168+
169+
for ( int i = 0; i < numSurfaces; i++ ) {
170+
bspSurface_t* surface = rendererSurfaces[i];
171+
172+
if ( surface->viewCount == -1 ) {
173+
numUnmergedSurfaces++;
174+
} else if ( surface->viewCount != oldViewCount ) {
175+
oldViewCount = surface->viewCount;
176+
numMergedSurfaces++;
177+
}
178+
}
146179

147-
if ( surface->shader->isPortal ) {
148-
// HACK: don't use VBO because when adding a portal we have to read back the verts CPU-side
180+
// Allocate merged surfaces
181+
world->mergedSurfaces = ( bspSurface_t* ) ri.Hunk_Alloc( sizeof( bspSurface_t ) * numMergedSurfaces, ha_pref::h_low );
182+
183+
// actually merge surfaces
184+
bspSurface_t* mergedSurf = world->mergedSurfaces;
185+
oldViewCount = -2;
186+
for ( int i = 0; i < numSurfaces; i++ ) {
187+
vec3_t bounds[2];
188+
int surfVerts = 0;
189+
int surfIndexes = 0;
190+
srfVBOMesh_t* vboSurf;
191+
bspSurface_t* surf1 = rendererSurfaces[i];
192+
193+
// skip unmergable surfaces
194+
if ( surf1->viewCount == -1 ) {
149195
continue;
150196
}
151197

152-
if ( surface->shader->autoSpriteMode != 0 ) {
153-
// don't use VBO because verts are rewritten each time based on view origin
198+
// skip surfaces that have already been merged
199+
if ( surf1->viewCount == oldViewCount ) {
154200
continue;
155201
}
156202

157-
if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID
158-
|| *surface->data == surfaceType_t::SF_TRIANGLES ) {
159-
coreSurfaces[numSurfaces++] = surface;
203+
oldViewCount = surf1->viewCount;
204+
205+
srfGeneric_t* srf1 = ( srfGeneric_t* ) surf1->data;
206+
int firstIndex = srf1->firstIndex;
207+
208+
// count verts and indexes and add bounds for the merged surface
209+
ClearBounds( bounds[0], bounds[1] );
210+
for ( int j = i; j < numSurfaces; j++ ) {
211+
bspSurface_t* surf2 = rendererSurfaces[j];
212+
213+
// stop merging when we hit a surface that can't be merged
214+
if ( surf2->viewCount != surf1->viewCount ) {
215+
break;
216+
}
217+
218+
srfGeneric_t* srf2 = ( srfGeneric_t* ) surf2->data;
219+
surfIndexes += srf2->numTriangles * 3;
220+
surfVerts += srf2->numVerts;
221+
BoundsAdd( bounds[0], bounds[1], srf2->bounds[0], srf2->bounds[1] );
160222
}
161-
}
162223

163-
qsort( coreSurfaces, numSurfaces, sizeof( bspSurface_t* ), LeafSurfaceCompare );
224+
if ( !surfIndexes || !surfVerts ) {
225+
continue;
226+
}
227+
228+
vboSurf = ( srfVBOMesh_t* ) ri.Hunk_Alloc( sizeof( *vboSurf ), ha_pref::h_low );
229+
*vboSurf = {};
230+
vboSurf->surfaceType = surfaceType_t::SF_VBO_MESH;
231+
232+
vboSurf->numTriangles = surfIndexes / 3;
233+
vboSurf->numVerts = surfVerts;
234+
vboSurf->firstIndex = firstIndex;
164235

165-
return coreSurfaces;
236+
vboSurf->lightmapNum = surf1->lightmapNum;
237+
vboSurf->vbo = world->vbo;
238+
vboSurf->ibo = world->ibo;
239+
240+
VectorCopy( bounds[0], vboSurf->bounds[0] );
241+
VectorCopy( bounds[1], vboSurf->bounds[1] );
242+
SphereFromBounds( vboSurf->bounds[0], vboSurf->bounds[1], vboSurf->origin, &vboSurf->radius );
243+
244+
mergedSurf->data = ( surfaceType_t* ) vboSurf;
245+
mergedSurf->fogIndex = surf1->fogIndex;
246+
mergedSurf->shader = surf1->shader;
247+
mergedSurf->lightmapNum = surf1->lightmapNum;
248+
mergedSurf->viewCount = -1;
249+
250+
// redirect view surfaces to this surf
251+
for ( int k = 0; k < world->numMarkSurfaces; k++ ) {
252+
bspSurface_t** view = world->viewSurfaces + k;
253+
254+
if ( ( *view )->viewCount == surf1->viewCount ) {
255+
*view = mergedSurf;
256+
}
257+
}
258+
259+
mergedSurf++;
260+
}
261+
262+
Log::Debug( "Processed %d surfaces into %d merged, %d unmerged", numSurfaces, numMergedSurfaces, numUnmergedSurfaces );
166263
}
167264

168265
/*
@@ -224,59 +321,30 @@ std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int nu
224321
std::vector<MaterialSurface> processedMaterialSurfaces;
225322
processedMaterialSurfaces.reserve( numSurfaces );
226323

324+
// std::unordered_map<TriEdge, TriIndex> triEdges;
325+
227326
int surfaceIndex = 0;
228327
for ( int k = 0; k < world->numSurfaces; k++ ) {
229328
bspSurface_t* surface = &world->surfaces[k];
230329

231-
if ( surface->shader->isPortal ) {
232-
continue;
233-
}
330+
MaterialSurface srf {};
234331

235-
if ( surface->shader->autoSpriteMode ) {
236-
continue;
237-
}
332+
srf.shader = surface->shader;
333+
srf.bspSurface = true;
334+
srf.fog = surface->fogIndex;
238335

239-
if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID
240-
|| *surface->data == surfaceType_t::SF_TRIANGLES ) {
241-
MaterialSurface srf {};
242-
243-
srf.shader = surface->shader;
244-
srf.bspSurface = true;
245-
srf.fog = surface->fogIndex;
246-
247-
switch ( *surface->data ) {
248-
case surfaceType_t::SF_FACE:
249-
srf.firstIndex = ( ( srfSurfaceFace_t* ) surface->data )->firstIndex;
250-
srf.count = ( ( srfSurfaceFace_t* ) surface->data )->numTriangles;
251-
srf.verts = ( ( srfSurfaceFace_t* ) surface->data )->verts;
252-
srf.tris = ( ( srfSurfaceFace_t* ) surface->data )->triangles;
253-
break;
254-
case surfaceType_t::SF_GRID:
255-
srf.firstIndex = ( ( srfGridMesh_t* ) surface->data )->firstIndex;
256-
srf.count = ( ( srfGridMesh_t* ) surface->data )->numTriangles;
257-
srf.verts = ( ( srfGridMesh_t* ) surface->data )->verts;
258-
srf.tris = ( ( srfGridMesh_t* ) surface->data )->triangles;
259-
break;
260-
case surfaceType_t::SF_TRIANGLES:
261-
srf.firstIndex = ( ( srfTriangles_t* ) surface->data )->firstIndex;
262-
srf.count = ( ( srfTriangles_t* ) surface->data )->numTriangles;
263-
srf.verts = ( ( srfTriangles_t* ) surface->data )->verts;
264-
srf.tris = ( ( srfTriangles_t* ) surface->data )->triangles;
265-
break;
266-
default:
267-
break;
268-
}
336+
srf.firstIndex = ( ( srfGeneric_t* ) surface->data )->firstIndex;
337+
srf.count = ( ( srfGeneric_t* ) surface->data )->numTriangles;
338+
srf.verts = ( ( srfGeneric_t* ) surface->data )->verts;
339+
srf.tris = ( ( srfGeneric_t* ) surface->data )->triangles;
269340

270-
materialSurfaces.emplace_back( srf );
271-
surfaceIndex++;
272-
}
341+
materialSurfaces.emplace_back( srf );
342+
surfaceIndex++;
273343
}
274344

275345
while ( materialSurfaces.size() ) {
276346
ProcessMaterialSurface( materialSurfaces.front(), materialSurfaces, processedMaterialSurfaces, verts, indices );
277347
}
278348

279-
// qsort( materialSurfaces, numSurfaces, sizeof( bspSurface_t* ), LeafSurfaceCompare );
280-
281349
return materialSurfaces;
282350
}

src/engine/renderer/GeometryOptimiser.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4242
#define MAX_MATERIAL_SURFACE_TRIS 64
4343
#define MAX_MATERIAL_SURFACE_DISTANCE 256
4444

45-
bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces );
45+
struct TriEdge {
46+
enum State : uint32_t {
47+
MERGEABLE_TRUE = BIT( 27 ),
48+
MERGEABLE_FALSE = BIT( 28 ),
49+
MERGEABLE_NOT_PROCESSED = BIT( 29 ),
50+
NONE = BIT( 30 )
51+
};
52+
53+
uint32_t index1;
54+
uint32_t index2;
55+
};
56+
57+
struct TriEdgeHasher {
58+
size_t operator()( const TriEdge& triEdge ) {
59+
return std::hash<uint32_t>{} ( triEdge.index1 ) ^ ( std::hash<uint32_t>{} ( triEdge.index2 ) << 16 );
60+
}
61+
};
62+
63+
struct TriIndex {
64+
int tri1 = -1;
65+
int tri2 = -1;
66+
};
67+
68+
void OptimiseMapGeometryCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces );
69+
void MergeLeafSurfacesCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces );
4670
std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int numSurfaces );
4771

4872
#endif // GEOMETRY_OPTIMISER_H

0 commit comments

Comments
 (0)