From 3eab5e9002b6457625e4e466637d284a4b9862f0 Mon Sep 17 00:00:00 2001 From: DS Date: Wed, 3 Jan 2024 21:56:38 +0100 Subject: [PATCH] Replace clientmap's MeshBufListList with a hashmap --- src/client/clientmap.cpp | 88 ++++++++++++++++++++++------------------ src/client/clientmap.h | 19 --------- 2 files changed, 49 insertions(+), 58 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index b831724b3..7224c6490 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -34,33 +34,43 @@ with this program; if not, write to the Free Software Foundation, Inc., #include -// struct MeshBufListList -void MeshBufListList::clear() -{ - for (auto &list : lists) - list.clear(); -} +namespace { + // A helper struct + struct MeshBufListMaps + { + struct MaterialHash + { + size_t operator()(const video::SMaterial &m) const noexcept + { + // Only hash first texture. Simple and fast. + return std::hash{}(m.TextureLayers[0].Texture); + } + }; -void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer) -{ - // Append to the correct layer - std::vector &list = lists[layer]; - const video::SMaterial &m = buf->getMaterial(); - for (MeshBufList &l : list) { - // comparing a full material is quite expensive so we don't do it if - // not even first texture is equal - if (l.m.TextureLayers[0].Texture != m.TextureLayers[0].Texture) - continue; + using MeshBufListMap = std::unordered_map< + video::SMaterial, + std::vector>, + MaterialHash>; - if (l.m == m) { - l.bufs.emplace_back(position, buf); - return; + std::array maps; + + void clear() + { + for (auto &map : maps) + map.clear(); } - } - MeshBufList l; - l.m = m; - l.bufs.emplace_back(position, buf); - list.emplace_back(l); + + void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer) + { + assert(layer < MAX_TILE_LAYERS); + + // Append to the correct layer + auto &map = maps[layer]; + const video::SMaterial &m = buf->getMaterial(); + auto &bufs = map[m]; // default constructs if non-existent + bufs.emplace_back(position, buf); + } + }; } 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 */ - MeshBufListList grouped_buffers; + MeshBufListMaps grouped_buffers; std::vector draw_order; video::SMaterial previous_material; @@ -793,7 +803,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) } else { // otherwise, group buffers across meshes - // using MeshBufListList + // using MeshBufListMaps for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { scene::IMesh *mesh = block_mesh->getMesh(layer); assert(mesh); @@ -819,11 +829,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) } // Capture draw order for all solid meshes - for (auto &lists : grouped_buffers.lists) { - for (MeshBufList &list : lists) { + for (auto &map : grouped_buffers.maps) { + for (auto &list : map) { // iterate in reverse to draw closest blocks first - for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) { - draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); + for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) { + 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 vertex_count = 0; - MeshBufListList grouped_buffers; + MeshBufListMaps grouped_buffers; std::vector draw_order; @@ -1144,7 +1154,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, } else { // otherwise, group buffers across meshes - // using MeshBufListList + // using MeshBufListMaps MapBlockMesh *mapBlockMesh = block->mesh; assert(mapBlockMesh); @@ -1167,18 +1177,18 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, } u32 buffer_count = 0; - for (auto &lists : grouped_buffers.lists) - for (MeshBufList &list : lists) - buffer_count += list.bufs.size(); + for (auto &map : grouped_buffers.maps) + for (auto &list : map) + buffer_count += list.second.size(); draw_order.reserve(draw_order.size() + buffer_count); // Capture draw order for all solid meshes - for (auto &lists : grouped_buffers.lists) { - for (MeshBufList &list : lists) { + for (auto &map : grouped_buffers.maps) { + for (auto &list : map) { // iterate in reverse to draw closest blocks first - for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) - draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); + for (auto it = list.second.rbegin(); it != list.second.rend(); ++it) + draw_order.emplace_back(it->first, it->second, it != list.second.rbegin()); } } diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 13c320d9a..eb9bf7d39 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -37,25 +37,6 @@ struct MapDrawControl bool show_wireframe = false; }; -struct MeshBufList -{ - video::SMaterial m; - std::vector> 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 lists[MAX_TILE_LAYERS]; - - void clear(); - void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer); -}; - class Client; class ITextureSource; class PartialMeshBuffer;