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>
// 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<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 add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
{
assert(layer < MAX_TILE_LAYERS);
void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
{
// Append to the correct layer
std::vector<MeshBufList> &list = lists[layer];
auto &map = maps[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;
if (l.m == m) {
l.bufs.emplace_back(position, buf);
return;
auto &bufs = map[m]; // default constructs if non-existent
bufs.emplace_back(position, buf);
}
}
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)
@ -737,7 +747,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
Draw the selected MapBlocks
*/
MeshBufListList grouped_buffers;
MeshBufListMaps grouped_buffers;
std::vector<DrawDescriptor> 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<DrawDescriptor> 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());
}
}

@ -37,25 +37,6 @@ struct MapDrawControl
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 ITextureSource;
class PartialMeshBuffer;