Replace clientmap's MeshBufListList with a hashmap

This commit is contained in:
DS 2024-01-03 21:56:38 +01:00 committed by GitHub
parent a22b1700a4
commit 3eab5e9002
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 58 deletions

@ -34,33 +34,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <queue> #include <queue>
// struct MeshBufListList namespace {
void MeshBufListList::clear() // A helper struct
struct MeshBufListMaps
{ {
for (auto &list : lists) struct MaterialHash
list.clear(); {
size_t operator()(const video::SMaterial &m) const noexcept
{
// Only hash first texture. Simple and fast.
return std::hash<video::ITexture *>{}(m.TextureLayers[0].Texture);
}
};
using MeshBufListMap = std::unordered_map<
video::SMaterial,
std::vector<std::pair<v3s16, scene::IMeshBuffer *>>,
MaterialHash>;
std::array<MeshBufListMap, MAX_TILE_LAYERS> maps;
void clear()
{
for (auto &map : maps)
map.clear();
} }
void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer) void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
{ {
assert(layer < MAX_TILE_LAYERS);
// Append to the correct layer // Append to the correct layer
std::vector<MeshBufList> &list = lists[layer]; auto &map = maps[layer];
const video::SMaterial &m = buf->getMaterial(); const video::SMaterial &m = buf->getMaterial();
for (MeshBufList &l : list) { auto &bufs = map[m]; // default constructs if non-existent
// comparing a full material is quite expensive so we don't do it if bufs.emplace_back(position, buf);
// not even first texture is equal
if (l.m.TextureLayers[0].Texture != m.TextureLayers[0].Texture)
continue;
if (l.m == m) {
l.bufs.emplace_back(position, buf);
return;
} }
} };
MeshBufList l;
l.m = m;
l.bufs.emplace_back(position, buf);
list.emplace_back(l);
} }
static void on_settings_changed(const std::string &name, void *data) static void on_settings_changed(const std::string &name, void *data)
@ -737,7 +747,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
Draw the selected MapBlocks Draw the selected MapBlocks
*/ */
MeshBufListList grouped_buffers; MeshBufListMaps grouped_buffers;
std::vector<DrawDescriptor> draw_order; std::vector<DrawDescriptor> draw_order;
video::SMaterial previous_material; video::SMaterial previous_material;
@ -793,7 +803,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
} }
else { else {
// otherwise, group buffers across meshes // otherwise, group buffers across meshes
// using MeshBufListList // using MeshBufListMaps
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
scene::IMesh *mesh = block_mesh->getMesh(layer); scene::IMesh *mesh = block_mesh->getMesh(layer);
assert(mesh); assert(mesh);
@ -819,11 +829,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
} }
// Capture draw order for all solid meshes // Capture draw order for all solid meshes
for (auto &lists : grouped_buffers.lists) { for (auto &map : grouped_buffers.maps) {
for (MeshBufList &list : lists) { for (auto &list : map) {
// iterate in reverse to draw closest blocks first // iterate in reverse to draw closest blocks first
for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) { for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) {
draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
} }
} }
} }
@ -1103,7 +1113,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
u32 drawcall_count = 0; u32 drawcall_count = 0;
u32 vertex_count = 0; u32 vertex_count = 0;
MeshBufListList grouped_buffers; MeshBufListMaps grouped_buffers;
std::vector<DrawDescriptor> draw_order; std::vector<DrawDescriptor> draw_order;
@ -1144,7 +1154,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
} }
else { else {
// otherwise, group buffers across meshes // otherwise, group buffers across meshes
// using MeshBufListList // using MeshBufListMaps
MapBlockMesh *mapBlockMesh = block->mesh; MapBlockMesh *mapBlockMesh = block->mesh;
assert(mapBlockMesh); assert(mapBlockMesh);
@ -1167,18 +1177,18 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
} }
u32 buffer_count = 0; u32 buffer_count = 0;
for (auto &lists : grouped_buffers.lists) for (auto &map : grouped_buffers.maps)
for (MeshBufList &list : lists) for (auto &list : map)
buffer_count += list.bufs.size(); buffer_count += list.second.size();
draw_order.reserve(draw_order.size() + buffer_count); draw_order.reserve(draw_order.size() + buffer_count);
// Capture draw order for all solid meshes // Capture draw order for all solid meshes
for (auto &lists : grouped_buffers.lists) { for (auto &map : grouped_buffers.maps) {
for (MeshBufList &list : lists) { for (auto &list : map) {
// iterate in reverse to draw closest blocks first // iterate in reverse to draw closest blocks first
for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) for (auto it = list.second.rbegin(); it != list.second.rend(); ++it)
draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); draw_order.emplace_back(it->first, it->second, it != list.second.rbegin());
} }
} }

@ -37,25 +37,6 @@ struct MapDrawControl
bool show_wireframe = false; bool show_wireframe = false;
}; };
struct MeshBufList
{
video::SMaterial m;
std::vector<std::pair<v3s16,scene::IMeshBuffer*>> bufs;
};
struct MeshBufListList
{
/*!
* Stores the mesh buffers of the world.
* The array index is the material's layer.
* The vector part groups vertices by material.
*/
std::vector<MeshBufList> lists[MAX_TILE_LAYERS];
void clear();
void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer);
};
class Client; class Client;
class ITextureSource; class ITextureSource;
class PartialMeshBuffer; class PartialMeshBuffer;