mesh_generator_thread.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. Minetest
  3. Copyright (C) 2013, 2017 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "mesh_generator_thread.h"
  17. #include "settings.h"
  18. #include "profiler.h"
  19. #include "client.h"
  20. #include "mapblock.h"
  21. #include "map.h"
  22. #include "util/directiontables.h"
  23. static class BlockPlaceholder {
  24. public:
  25. MapNode data[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
  26. BlockPlaceholder()
  27. {
  28. for (std::size_t i = 0; i < MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; i++)
  29. data[i] = MapNode(CONTENT_IGNORE);
  30. }
  31. } block_placeholder;
  32. /*
  33. QueuedMeshUpdate
  34. */
  35. QueuedMeshUpdate::~QueuedMeshUpdate()
  36. {
  37. delete data;
  38. }
  39. /*
  40. MeshUpdateQueue
  41. */
  42. MeshUpdateQueue::MeshUpdateQueue(Client *client):
  43. m_client(client)
  44. {
  45. m_cache_enable_shaders = g_settings->getBool("enable_shaders");
  46. m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
  47. }
  48. MeshUpdateQueue::~MeshUpdateQueue()
  49. {
  50. MutexAutoLock lock(m_mutex);
  51. for (QueuedMeshUpdate *q : m_queue) {
  52. for (auto block : q->map_blocks)
  53. if (block)
  54. block->refDrop();
  55. delete q;
  56. }
  57. }
  58. bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent)
  59. {
  60. MapBlock *main_block = map->getBlockNoCreateNoEx(p);
  61. if (!main_block)
  62. return false;
  63. MutexAutoLock lock(m_mutex);
  64. MeshGrid mesh_grid = m_client->getMeshGrid();
  65. // Mesh is placed at the corner block of a chunk
  66. // (where all coordinate are divisible by the chunk size)
  67. v3s16 mesh_position(mesh_grid.getMeshPos(p));
  68. /*
  69. Mark the block as urgent if requested
  70. */
  71. if (urgent)
  72. m_urgents.insert(mesh_position);
  73. /*
  74. Find if block is already in queue.
  75. If it is, update the data and quit.
  76. */
  77. for (QueuedMeshUpdate *q : m_queue) {
  78. if (q->p == mesh_position) {
  79. // NOTE: We are not adding a new position to the queue, thus
  80. // refcount_from_queue stays the same.
  81. if(ack_block_to_server)
  82. q->ack_list.push_back(p);
  83. q->crack_level = m_client->getCrackLevel();
  84. q->crack_pos = m_client->getCrackPos();
  85. q->urgent |= urgent;
  86. v3s16 pos;
  87. int i = 0;
  88. for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_grid.cell_size; pos.X++)
  89. for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_grid.cell_size; pos.Z++)
  90. for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_grid.cell_size; pos.Y++) {
  91. if (!q->map_blocks[i]) {
  92. MapBlock *block = map->getBlockNoCreateNoEx(pos);
  93. if (block) {
  94. block->refGrab();
  95. q->map_blocks[i] = block;
  96. }
  97. }
  98. i++;
  99. }
  100. return true;
  101. }
  102. }
  103. /*
  104. Make a list of blocks necessary for mesh generation and lock the blocks in memory.
  105. */
  106. std::vector<MapBlock *> map_blocks;
  107. map_blocks.reserve((mesh_grid.cell_size+2)*(mesh_grid.cell_size+2)*(mesh_grid.cell_size+2));
  108. v3s16 pos;
  109. for (pos.X = mesh_position.X - 1; pos.X <= mesh_position.X + mesh_grid.cell_size; pos.X++)
  110. for (pos.Z = mesh_position.Z - 1; pos.Z <= mesh_position.Z + mesh_grid.cell_size; pos.Z++)
  111. for (pos.Y = mesh_position.Y - 1; pos.Y <= mesh_position.Y + mesh_grid.cell_size; pos.Y++) {
  112. MapBlock *block = map->getBlockNoCreateNoEx(pos);
  113. map_blocks.push_back(block);
  114. if (block)
  115. block->refGrab();
  116. }
  117. /*
  118. Add the block
  119. */
  120. QueuedMeshUpdate *q = new QueuedMeshUpdate;
  121. q->p = mesh_position;
  122. if(ack_block_to_server)
  123. q->ack_list.push_back(p);
  124. q->crack_level = m_client->getCrackLevel();
  125. q->crack_pos = m_client->getCrackPos();
  126. q->urgent = urgent;
  127. q->map_blocks = std::move(map_blocks);
  128. m_queue.push_back(q);
  129. return true;
  130. }
  131. // Returned pointer must be deleted
  132. // Returns NULL if queue is empty
  133. QueuedMeshUpdate *MeshUpdateQueue::pop()
  134. {
  135. QueuedMeshUpdate *result = NULL;
  136. {
  137. MutexAutoLock lock(m_mutex);
  138. bool must_be_urgent = !m_urgents.empty();
  139. for (std::vector<QueuedMeshUpdate*>::iterator i = m_queue.begin();
  140. i != m_queue.end(); ++i) {
  141. QueuedMeshUpdate *q = *i;
  142. if (must_be_urgent && m_urgents.count(q->p) == 0)
  143. continue;
  144. // Make sure no two threads are processing the same mapblock, as that causes racing conditions
  145. if (m_inflight_blocks.find(q->p) != m_inflight_blocks.end())
  146. continue;
  147. m_queue.erase(i);
  148. m_urgents.erase(q->p);
  149. m_inflight_blocks.insert(q->p);
  150. result = q;
  151. break;
  152. }
  153. }
  154. if (result)
  155. fillDataFromMapBlocks(result);
  156. return result;
  157. }
  158. void MeshUpdateQueue::done(v3s16 pos)
  159. {
  160. MutexAutoLock lock(m_mutex);
  161. m_inflight_blocks.erase(pos);
  162. }
  163. void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
  164. {
  165. auto mesh_grid = m_client->getMeshGrid();
  166. MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size, m_cache_enable_shaders);
  167. q->data = data;
  168. data->fillBlockDataBegin(q->p);
  169. v3s16 pos;
  170. int i = 0;
  171. for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_grid.cell_size; pos.X++)
  172. for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_grid.cell_size; pos.Z++)
  173. for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_grid.cell_size; pos.Y++) {
  174. MapBlock *block = q->map_blocks[i++];
  175. data->fillBlockData(pos, block ? block->getData() : block_placeholder.data);
  176. }
  177. data->setCrack(q->crack_level, q->crack_pos);
  178. data->setSmoothLighting(m_cache_smooth_lighting);
  179. }
  180. /*
  181. MeshUpdateWorkerThread
  182. */
  183. MeshUpdateWorkerThread::MeshUpdateWorkerThread(Client *client, MeshUpdateQueue *queue_in, MeshUpdateManager *manager, v3s16 *camera_offset) :
  184. UpdateThread("Mesh"), m_client(client), m_queue_in(queue_in), m_manager(manager), m_camera_offset(camera_offset)
  185. {
  186. m_generation_interval = g_settings->getU16("mesh_generation_interval");
  187. m_generation_interval = rangelim(m_generation_interval, 0, 50);
  188. }
  189. void MeshUpdateWorkerThread::doUpdate()
  190. {
  191. QueuedMeshUpdate *q;
  192. while ((q = m_queue_in->pop())) {
  193. if (m_generation_interval)
  194. sleep_ms(m_generation_interval);
  195. ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)");
  196. MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data, *m_camera_offset);
  197. MeshUpdateResult r;
  198. r.p = q->p;
  199. r.mesh = mesh_new;
  200. r.solid_sides = get_solid_sides(q->data);
  201. r.ack_list = std::move(q->ack_list);
  202. r.urgent = q->urgent;
  203. r.map_blocks = q->map_blocks;
  204. m_manager->putResult(r);
  205. m_queue_in->done(q->p);
  206. delete q;
  207. }
  208. }
  209. /*
  210. MeshUpdateManager
  211. */
  212. MeshUpdateManager::MeshUpdateManager(Client *client):
  213. m_queue_in(client)
  214. {
  215. int number_of_threads = rangelim(g_settings->getS32("mesh_generation_threads"), 0, 8);
  216. // Automatically use 33% of the system cores for mesh generation, max 4
  217. if (number_of_threads == 0)
  218. number_of_threads = MYMIN(4, Thread::getNumberOfProcessors() / 3);
  219. // use at least one thread
  220. number_of_threads = MYMAX(1, number_of_threads);
  221. infostream << "MeshUpdateManager: using " << number_of_threads << " threads" << std::endl;
  222. for (int i = 0; i < number_of_threads; i++)
  223. m_workers.push_back(std::make_unique<MeshUpdateWorkerThread>(client, &m_queue_in, this, &m_camera_offset));
  224. }
  225. void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
  226. bool urgent, bool update_neighbors)
  227. {
  228. static thread_local const bool many_neighbors =
  229. g_settings->getBool("smooth_lighting")
  230. && !g_settings->getFlag("performance_tradeoffs");
  231. if (!m_queue_in.addBlock(map, p, ack_block_to_server, urgent)) {
  232. warningstream << "Update requested for non-existent block at ("
  233. << p.X << ", " << p.Y << ", " << p.Z << ")" << std::endl;
  234. return;
  235. }
  236. if (update_neighbors) {
  237. if (many_neighbors) {
  238. for (v3s16 dp : g_26dirs)
  239. m_queue_in.addBlock(map, p + dp, false, urgent);
  240. } else {
  241. for (v3s16 dp : g_6dirs)
  242. m_queue_in.addBlock(map, p + dp, false, urgent);
  243. }
  244. }
  245. deferUpdate();
  246. }
  247. void MeshUpdateManager::putResult(const MeshUpdateResult &result)
  248. {
  249. if (result.urgent)
  250. m_queue_out_urgent.push_back(result);
  251. else
  252. m_queue_out.push_back(result);
  253. }
  254. bool MeshUpdateManager::getNextResult(MeshUpdateResult &r)
  255. {
  256. if (!m_queue_out_urgent.empty()) {
  257. r = m_queue_out_urgent.pop_frontNoEx();
  258. return true;
  259. }
  260. if (!m_queue_out.empty()) {
  261. r = m_queue_out.pop_frontNoEx();
  262. return true;
  263. }
  264. return false;
  265. }
  266. void MeshUpdateManager::deferUpdate()
  267. {
  268. for (auto &thread : m_workers)
  269. thread->deferUpdate();
  270. }
  271. void MeshUpdateManager::start()
  272. {
  273. for (auto &thread: m_workers)
  274. thread->start();
  275. }
  276. void MeshUpdateManager::stop()
  277. {
  278. for (auto &thread: m_workers)
  279. thread->stop();
  280. }
  281. void MeshUpdateManager::wait()
  282. {
  283. for (auto &thread: m_workers)
  284. thread->wait();
  285. }
  286. bool MeshUpdateManager::isRunning()
  287. {
  288. for (auto &thread: m_workers)
  289. if (thread->isRunning())
  290. return true;
  291. return false;
  292. }