draw_queue.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #pragma once
  2. #include "ground/firecamp_gpu.h"
  3. #include "ground/grass_gpu.h"
  4. #include "ground/olive_gpu.h"
  5. #include "ground/pine_gpu.h"
  6. #include "ground/plant_gpu.h"
  7. #include "ground/stone_gpu.h"
  8. #include "ground/terrain_gpu.h"
  9. #include "primitive_batch.h"
  10. #include <QMatrix4x4>
  11. #include <QVector3D>
  12. #include <algorithm>
  13. #include <cstddef>
  14. #include <cstdint>
  15. #include <variant>
  16. #include <vector>
  17. namespace Render::GL {
  18. class Mesh;
  19. class Texture;
  20. class Buffer;
  21. class Shader;
  22. } // namespace Render::GL
  23. namespace Render::GL {
  24. constexpr int k_sort_key_bucket_shift = 56;
  25. struct MeshCmd {
  26. Mesh *mesh = nullptr;
  27. Texture *texture = nullptr;
  28. QMatrix4x4 model;
  29. QMatrix4x4 mvp;
  30. QVector3D color{1, 1, 1};
  31. float alpha = 1.0F;
  32. int materialId = 0;
  33. class Shader *shader = nullptr;
  34. };
  35. struct CylinderCmd {
  36. QVector3D start{0.0F, -0.5F, 0.0F};
  37. QVector3D end{0.0F, 0.5F, 0.0F};
  38. QVector3D color{1.0F, 1.0F, 1.0F};
  39. float radius = 1.0F;
  40. float alpha = 1.0F;
  41. };
  42. struct FogInstanceData {
  43. QVector3D center{0.0F, 0.25F, 0.0F};
  44. QVector3D color{0.05F, 0.05F, 0.05F};
  45. float alpha = 1.0F;
  46. float size = 1.0F;
  47. };
  48. struct FogBatchCmd {
  49. const FogInstanceData *instances = nullptr;
  50. std::size_t count = 0;
  51. };
  52. struct GrassBatchCmd {
  53. Buffer *instanceBuffer = nullptr;
  54. std::size_t instance_count = 0;
  55. GrassBatchParams params;
  56. };
  57. struct StoneBatchCmd {
  58. Buffer *instanceBuffer = nullptr;
  59. std::size_t instance_count = 0;
  60. StoneBatchParams params;
  61. };
  62. struct PlantBatchCmd {
  63. Buffer *instanceBuffer = nullptr;
  64. std::size_t instance_count = 0;
  65. PlantBatchParams params;
  66. };
  67. struct PineBatchCmd {
  68. Buffer *instanceBuffer = nullptr;
  69. std::size_t instance_count = 0;
  70. PineBatchParams params;
  71. };
  72. struct OliveBatchCmd {
  73. Buffer *instanceBuffer = nullptr;
  74. std::size_t instance_count = 0;
  75. OliveBatchParams params;
  76. };
  77. struct FireCampBatchCmd {
  78. Buffer *instanceBuffer = nullptr;
  79. std::size_t instance_count = 0;
  80. FireCampBatchParams params;
  81. };
  82. struct TerrainChunkCmd {
  83. Mesh *mesh = nullptr;
  84. QMatrix4x4 model;
  85. TerrainChunkParams params;
  86. std::uint16_t sortKey = 0x8000U;
  87. bool depthWrite = true;
  88. float depthBias = 0.0F;
  89. };
  90. struct GridCmd {
  91. QMatrix4x4 model;
  92. QMatrix4x4 mvp;
  93. QVector3D color{0.2F, 0.25F, 0.2F};
  94. float cellSize = 1.0F;
  95. float thickness = 0.06F;
  96. float extent = 50.0F;
  97. };
  98. struct SelectionRingCmd {
  99. QMatrix4x4 model;
  100. QMatrix4x4 mvp;
  101. QVector3D color{0, 0, 0};
  102. float alphaInner = 0.6F;
  103. float alphaOuter = 0.25F;
  104. };
  105. struct SelectionSmokeCmd {
  106. QMatrix4x4 model;
  107. QMatrix4x4 mvp;
  108. QVector3D color{1, 1, 1};
  109. float baseAlpha = 0.15F;
  110. };
  111. using DrawCmd =
  112. std::variant<GridCmd, SelectionRingCmd, SelectionSmokeCmd, CylinderCmd,
  113. MeshCmd, FogBatchCmd, GrassBatchCmd, StoneBatchCmd,
  114. PlantBatchCmd, PineBatchCmd, OliveBatchCmd, FireCampBatchCmd,
  115. TerrainChunkCmd, PrimitiveBatchCmd>;
  116. enum class DrawCmdType : std::uint8_t {
  117. Grid = 0,
  118. SelectionRing = 1,
  119. SelectionSmoke = 2,
  120. Cylinder = 3,
  121. Mesh = 4,
  122. FogBatch = 5,
  123. GrassBatch = 6,
  124. StoneBatch = 7,
  125. PlantBatch = 8,
  126. PineBatch = 9,
  127. OliveBatch = 10,
  128. FireCampBatch = 11,
  129. TerrainChunk = 12,
  130. PrimitiveBatch = 13
  131. };
  132. constexpr std::size_t MeshCmdIndex =
  133. static_cast<std::size_t>(DrawCmdType::Mesh);
  134. constexpr std::size_t GridCmdIndex =
  135. static_cast<std::size_t>(DrawCmdType::Grid);
  136. constexpr std::size_t SelectionRingCmdIndex =
  137. static_cast<std::size_t>(DrawCmdType::SelectionRing);
  138. constexpr std::size_t SelectionSmokeCmdIndex =
  139. static_cast<std::size_t>(DrawCmdType::SelectionSmoke);
  140. constexpr std::size_t CylinderCmdIndex =
  141. static_cast<std::size_t>(DrawCmdType::Cylinder);
  142. constexpr std::size_t FogBatchCmdIndex =
  143. static_cast<std::size_t>(DrawCmdType::FogBatch);
  144. constexpr std::size_t GrassBatchCmdIndex =
  145. static_cast<std::size_t>(DrawCmdType::GrassBatch);
  146. constexpr std::size_t StoneBatchCmdIndex =
  147. static_cast<std::size_t>(DrawCmdType::StoneBatch);
  148. constexpr std::size_t PlantBatchCmdIndex =
  149. static_cast<std::size_t>(DrawCmdType::PlantBatch);
  150. constexpr std::size_t PineBatchCmdIndex =
  151. static_cast<std::size_t>(DrawCmdType::PineBatch);
  152. constexpr std::size_t OliveBatchCmdIndex =
  153. static_cast<std::size_t>(DrawCmdType::OliveBatch);
  154. constexpr std::size_t FireCampBatchCmdIndex =
  155. static_cast<std::size_t>(DrawCmdType::FireCampBatch);
  156. constexpr std::size_t TerrainChunkCmdIndex =
  157. static_cast<std::size_t>(DrawCmdType::TerrainChunk);
  158. constexpr std::size_t PrimitiveBatchCmdIndex =
  159. static_cast<std::size_t>(DrawCmdType::PrimitiveBatch);
  160. inline auto drawCmdType(const DrawCmd &cmd) -> DrawCmdType {
  161. return static_cast<DrawCmdType>(cmd.index());
  162. }
  163. class DrawQueue {
  164. public:
  165. void clear() { m_items.clear(); }
  166. void submit(const MeshCmd &c) { m_items.emplace_back(c); }
  167. void submit(const GridCmd &c) { m_items.emplace_back(c); }
  168. void submit(const SelectionRingCmd &c) { m_items.emplace_back(c); }
  169. void submit(const SelectionSmokeCmd &c) { m_items.emplace_back(c); }
  170. void submit(const CylinderCmd &c) { m_items.emplace_back(c); }
  171. void submit(const FogBatchCmd &c) { m_items.emplace_back(c); }
  172. void submit(const GrassBatchCmd &c) { m_items.emplace_back(c); }
  173. void submit(const StoneBatchCmd &c) { m_items.emplace_back(c); }
  174. void submit(const PlantBatchCmd &c) { m_items.emplace_back(c); }
  175. void submit(const PineBatchCmd &c) { m_items.emplace_back(c); }
  176. void submit(const OliveBatchCmd &c) { m_items.emplace_back(c); }
  177. void submit(const FireCampBatchCmd &c) { m_items.emplace_back(c); }
  178. void submit(const TerrainChunkCmd &c) { m_items.emplace_back(c); }
  179. void submit(const PrimitiveBatchCmd &c) { m_items.emplace_back(c); }
  180. [[nodiscard]] auto empty() const -> bool { return m_items.empty(); }
  181. [[nodiscard]] auto size() const -> std::size_t { return m_items.size(); }
  182. [[nodiscard]] auto getSorted(std::size_t i) const -> const DrawCmd & {
  183. return m_items[m_sortIndices[i]];
  184. }
  185. [[nodiscard]] auto items() const -> const std::vector<DrawCmd> & {
  186. return m_items;
  187. }
  188. void sortForBatching() {
  189. const std::size_t count = m_items.size();
  190. m_sortKeys.resize(count);
  191. m_sortIndices.resize(count);
  192. for (std::size_t i = 0; i < count; ++i) {
  193. m_sortIndices[i] = static_cast<uint32_t>(i);
  194. m_sortKeys[i] = computeSortKey(m_items[i]);
  195. }
  196. if (count >= 2) {
  197. radixSortTwoPass(count);
  198. }
  199. }
  200. private:
  201. void radixSortTwoPass(std::size_t count) {
  202. constexpr int BUCKETS = 256;
  203. m_tempIndices.resize(count);
  204. {
  205. int histogram[BUCKETS] = {0};
  206. for (std::size_t i = 0; i < count; ++i) {
  207. auto const bucket =
  208. static_cast<uint8_t>(m_sortKeys[i] >> k_sort_key_bucket_shift);
  209. ++histogram[bucket];
  210. }
  211. int offsets[BUCKETS];
  212. offsets[0] = 0;
  213. for (int i = 1; i < BUCKETS; ++i) {
  214. offsets[i] = offsets[i - 1] + histogram[i - 1];
  215. }
  216. for (std::size_t i = 0; i < count; ++i) {
  217. auto const bucket = static_cast<uint8_t>(m_sortKeys[m_sortIndices[i]] >>
  218. k_sort_key_bucket_shift);
  219. m_tempIndices[offsets[bucket]++] = m_sortIndices[i];
  220. }
  221. }
  222. {
  223. int histogram[BUCKETS] = {0};
  224. for (std::size_t i = 0; i < count; ++i) {
  225. uint8_t const bucket =
  226. static_cast<uint8_t>(m_sortKeys[m_tempIndices[i]] >> 48) & 0xFF;
  227. ++histogram[bucket];
  228. }
  229. int offsets[BUCKETS];
  230. offsets[0] = 0;
  231. for (int i = 1; i < BUCKETS; ++i) {
  232. offsets[i] = offsets[i - 1] + histogram[i - 1];
  233. }
  234. for (std::size_t i = 0; i < count; ++i) {
  235. uint8_t const bucket =
  236. static_cast<uint8_t>(m_sortKeys[m_tempIndices[i]] >> 48) & 0xFF;
  237. m_sortIndices[offsets[bucket]++] = m_tempIndices[i];
  238. }
  239. }
  240. }
  241. [[nodiscard]] static auto computeSortKey(const DrawCmd &cmd) -> uint64_t {
  242. enum class RenderOrder : uint8_t {
  243. TerrainChunk = 0,
  244. GrassBatch = 1,
  245. StoneBatch = 2,
  246. PlantBatch = 3,
  247. PineBatch = 4,
  248. OliveBatch = 5,
  249. FireCampBatch = 6,
  250. PrimitiveBatch = 7,
  251. Mesh = 8,
  252. Cylinder = 9,
  253. FogBatch = 10,
  254. SelectionSmoke = 11,
  255. Grid = 12,
  256. SelectionRing = 15
  257. };
  258. static constexpr uint8_t kTypeOrder[] = {
  259. static_cast<uint8_t>(RenderOrder::Grid),
  260. static_cast<uint8_t>(RenderOrder::SelectionRing),
  261. static_cast<uint8_t>(RenderOrder::SelectionSmoke),
  262. static_cast<uint8_t>(RenderOrder::Cylinder),
  263. static_cast<uint8_t>(RenderOrder::Mesh),
  264. static_cast<uint8_t>(RenderOrder::FogBatch),
  265. static_cast<uint8_t>(RenderOrder::GrassBatch),
  266. static_cast<uint8_t>(RenderOrder::StoneBatch),
  267. static_cast<uint8_t>(RenderOrder::PlantBatch),
  268. static_cast<uint8_t>(RenderOrder::PineBatch),
  269. static_cast<uint8_t>(RenderOrder::OliveBatch),
  270. static_cast<uint8_t>(RenderOrder::FireCampBatch),
  271. static_cast<uint8_t>(RenderOrder::TerrainChunk),
  272. static_cast<uint8_t>(RenderOrder::PrimitiveBatch)};
  273. const std::size_t typeIndex = cmd.index();
  274. constexpr std::size_t typeCount =
  275. sizeof(kTypeOrder) / sizeof(kTypeOrder[0]);
  276. const uint8_t typeOrder = typeIndex < typeCount
  277. ? kTypeOrder[typeIndex]
  278. : static_cast<uint8_t>(typeIndex);
  279. uint64_t key = static_cast<uint64_t>(typeOrder) << 56;
  280. if (cmd.index() == MeshCmdIndex) {
  281. const auto &mesh = std::get<MeshCmdIndex>(cmd);
  282. uint64_t const texPtr =
  283. reinterpret_cast<uintptr_t>(mesh.texture) & 0x0000FFFFFFFFFFFF;
  284. key |= texPtr;
  285. } else if (cmd.index() == GrassBatchCmdIndex) {
  286. const auto &grass = std::get<GrassBatchCmdIndex>(cmd);
  287. uint64_t const bufferPtr =
  288. reinterpret_cast<uintptr_t>(grass.instanceBuffer) &
  289. 0x0000FFFFFFFFFFFF;
  290. key |= bufferPtr;
  291. } else if (cmd.index() == StoneBatchCmdIndex) {
  292. const auto &stone = std::get<StoneBatchCmdIndex>(cmd);
  293. uint64_t const bufferPtr =
  294. reinterpret_cast<uintptr_t>(stone.instanceBuffer) &
  295. 0x0000FFFFFFFFFFFF;
  296. key |= bufferPtr;
  297. } else if (cmd.index() == PlantBatchCmdIndex) {
  298. const auto &plant = std::get<PlantBatchCmdIndex>(cmd);
  299. uint64_t const bufferPtr =
  300. reinterpret_cast<uintptr_t>(plant.instanceBuffer) &
  301. 0x0000FFFFFFFFFFFF;
  302. key |= bufferPtr;
  303. } else if (cmd.index() == PineBatchCmdIndex) {
  304. const auto &pine = std::get<PineBatchCmdIndex>(cmd);
  305. uint64_t const bufferPtr =
  306. reinterpret_cast<uintptr_t>(pine.instanceBuffer) & 0x0000FFFFFFFFFFFF;
  307. key |= bufferPtr;
  308. } else if (cmd.index() == OliveBatchCmdIndex) {
  309. const auto &olive = std::get<OliveBatchCmdIndex>(cmd);
  310. uint64_t const bufferPtr =
  311. reinterpret_cast<uintptr_t>(olive.instanceBuffer) &
  312. 0x0000FFFFFFFFFFFF;
  313. key |= bufferPtr;
  314. } else if (cmd.index() == FireCampBatchCmdIndex) {
  315. const auto &firecamp = std::get<FireCampBatchCmdIndex>(cmd);
  316. uint64_t const bufferPtr =
  317. reinterpret_cast<uintptr_t>(firecamp.instanceBuffer) &
  318. 0x0000FFFFFFFFFFFF;
  319. key |= bufferPtr;
  320. } else if (cmd.index() == TerrainChunkCmdIndex) {
  321. const auto &terrain = std::get<TerrainChunkCmdIndex>(cmd);
  322. auto const sortByte =
  323. static_cast<uint64_t>((terrain.sortKey >> 8) & 0xFFU);
  324. key |= sortByte << 48;
  325. uint64_t const meshPtr =
  326. reinterpret_cast<uintptr_t>(terrain.mesh) & 0x0000FFFFFFFFFFFFU;
  327. key |= meshPtr;
  328. } else if (cmd.index() == PrimitiveBatchCmdIndex) {
  329. const auto &prim = std::get<PrimitiveBatchCmdIndex>(cmd);
  330. key |= static_cast<uint64_t>(prim.type) << 48;
  331. key |= static_cast<uint64_t>(prim.instanceCount() & 0xFFFFFFFF);
  332. }
  333. return key;
  334. }
  335. std::vector<DrawCmd> m_items;
  336. std::vector<uint32_t> m_sortIndices;
  337. std::vector<uint64_t> m_sortKeys;
  338. std::vector<uint32_t> m_tempIndices;
  339. };
  340. } // namespace Render::GL