primitive_batch_pipeline.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #include "primitive_batch_pipeline.h"
  2. #include "../backend.h"
  3. #include "../mesh.h"
  4. #include "../primitives.h"
  5. #include "../render_constants.h"
  6. #include <GL/gl.h>
  7. #include <QOpenGLContext>
  8. #include <algorithm>
  9. #include <cstddef>
  10. namespace Render::GL::BackendPipelines {
  11. using namespace Render::GL::VertexAttrib;
  12. using namespace Render::GL::ComponentCount;
  13. PrimitiveBatchPipeline::PrimitiveBatchPipeline(ShaderCache *shaderCache)
  14. : m_shader_cache(shaderCache) {}
  15. PrimitiveBatchPipeline::~PrimitiveBatchPipeline() { shutdown(); }
  16. auto PrimitiveBatchPipeline::initialize() -> bool {
  17. initializeOpenGLFunctions();
  18. if (m_shader_cache == nullptr) {
  19. return false;
  20. }
  21. m_shader = m_shader_cache->get(QStringLiteral("primitive_instanced"));
  22. if (m_shader == nullptr) {
  23. return false;
  24. }
  25. initialize_sphere_vao();
  26. initialize_cylinder_vao();
  27. initialize_cone_vao();
  28. cacheUniforms();
  29. m_initialized = true;
  30. return true;
  31. }
  32. void PrimitiveBatchPipeline::shutdown() {
  33. shutdown_vaos();
  34. m_initialized = false;
  35. }
  36. void PrimitiveBatchPipeline::cacheUniforms() {
  37. if (m_shader != nullptr) {
  38. m_uniforms.view_proj = m_shader->uniformHandle("u_viewProj");
  39. m_uniforms.light_dir = m_shader->uniformHandle("u_lightDir");
  40. m_uniforms.ambient_strength = m_shader->uniformHandle("u_ambientStrength");
  41. }
  42. }
  43. void PrimitiveBatchPipeline::begin_frame() {}
  44. void PrimitiveBatchPipeline::setup_instance_attributes(GLuint vao,
  45. GLuint instance_buffer) {
  46. glBindVertexArray(vao);
  47. glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
  48. const auto stride = static_cast<GLsizei>(sizeof(GL::PrimitiveInstanceGpu));
  49. glEnableVertexAttribArray(3);
  50. glVertexAttribPointer(
  51. 3, Vec4, GL_FLOAT, GL_FALSE, stride,
  52. reinterpret_cast<void *>(offsetof(GL::PrimitiveInstanceGpu, model_col0)));
  53. glVertexAttribDivisor(3, 1);
  54. glEnableVertexAttribArray(4);
  55. glVertexAttribPointer(
  56. 4, Vec4, GL_FLOAT, GL_FALSE, stride,
  57. reinterpret_cast<void *>(offsetof(GL::PrimitiveInstanceGpu, model_col1)));
  58. glVertexAttribDivisor(4, 1);
  59. glEnableVertexAttribArray(5);
  60. glVertexAttribPointer(
  61. 5, Vec4, GL_FLOAT, GL_FALSE, stride,
  62. reinterpret_cast<void *>(offsetof(GL::PrimitiveInstanceGpu, model_col2)));
  63. glVertexAttribDivisor(5, 1);
  64. glEnableVertexAttribArray(6);
  65. glVertexAttribPointer(6, Vec4, GL_FLOAT, GL_FALSE, stride,
  66. reinterpret_cast<void *>(
  67. offsetof(GL::PrimitiveInstanceGpu, color_alpha)));
  68. glVertexAttribDivisor(6, 1);
  69. glBindVertexArray(0);
  70. }
  71. void PrimitiveBatchPipeline::initialize_sphere_vao() {
  72. Mesh *unit = getUnitSphere();
  73. if (unit == nullptr) {
  74. return;
  75. }
  76. const auto &vertices = unit->getVertices();
  77. const auto &indices = unit->getIndices();
  78. if (vertices.empty() || indices.empty()) {
  79. return;
  80. }
  81. glGenVertexArrays(1, &m_sphere_vao);
  82. glBindVertexArray(m_sphere_vao);
  83. glGenBuffers(1, &m_sphere_vertex_buffer);
  84. glBindBuffer(GL_ARRAY_BUFFER, m_sphere_vertex_buffer);
  85. glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex),
  86. vertices.data(), GL_STATIC_DRAW);
  87. glGenBuffers(1, &m_sphere_index_buffer);
  88. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sphere_index_buffer);
  89. glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int),
  90. indices.data(), GL_STATIC_DRAW);
  91. m_sphere_index_count = static_cast<GLsizei>(indices.size());
  92. glEnableVertexAttribArray(Position);
  93. glVertexAttribPointer(Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  94. reinterpret_cast<void *>(offsetof(Vertex, position)));
  95. glEnableVertexAttribArray(Normal);
  96. glVertexAttribPointer(Normal, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  97. reinterpret_cast<void *>(offsetof(Vertex, normal)));
  98. glEnableVertexAttribArray(TexCoord);
  99. glVertexAttribPointer(TexCoord, Vec2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  100. reinterpret_cast<void *>(offsetof(Vertex, tex_coord)));
  101. glGenBuffers(1, &m_sphere_instance_buffer);
  102. glBindBuffer(GL_ARRAY_BUFFER, m_sphere_instance_buffer);
  103. m_sphere_instance_capacity = k_default_instance_capacity;
  104. glBufferData(GL_ARRAY_BUFFER,
  105. m_sphere_instance_capacity * sizeof(GL::PrimitiveInstanceGpu),
  106. nullptr, GL_DYNAMIC_DRAW);
  107. setup_instance_attributes(m_sphere_vao, m_sphere_instance_buffer);
  108. glBindVertexArray(0);
  109. }
  110. void PrimitiveBatchPipeline::initialize_cylinder_vao() {
  111. Mesh *unit = getUnitCylinder();
  112. if (unit == nullptr) {
  113. return;
  114. }
  115. const auto &vertices = unit->getVertices();
  116. const auto &indices = unit->getIndices();
  117. if (vertices.empty() || indices.empty()) {
  118. return;
  119. }
  120. glGenVertexArrays(1, &m_cylinder_vao);
  121. glBindVertexArray(m_cylinder_vao);
  122. glGenBuffers(1, &m_cylinder_vertex_buffer);
  123. glBindBuffer(GL_ARRAY_BUFFER, m_cylinder_vertex_buffer);
  124. glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex),
  125. vertices.data(), GL_STATIC_DRAW);
  126. glGenBuffers(1, &m_cylinder_index_buffer);
  127. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_cylinder_index_buffer);
  128. glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int),
  129. indices.data(), GL_STATIC_DRAW);
  130. m_cylinder_index_count = static_cast<GLsizei>(indices.size());
  131. glEnableVertexAttribArray(Position);
  132. glVertexAttribPointer(Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  133. reinterpret_cast<void *>(offsetof(Vertex, position)));
  134. glEnableVertexAttribArray(Normal);
  135. glVertexAttribPointer(Normal, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  136. reinterpret_cast<void *>(offsetof(Vertex, normal)));
  137. glEnableVertexAttribArray(TexCoord);
  138. glVertexAttribPointer(TexCoord, Vec2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  139. reinterpret_cast<void *>(offsetof(Vertex, tex_coord)));
  140. glGenBuffers(1, &m_cylinder_instance_buffer);
  141. glBindBuffer(GL_ARRAY_BUFFER, m_cylinder_instance_buffer);
  142. m_cylinder_instance_capacity = k_default_instance_capacity;
  143. glBufferData(GL_ARRAY_BUFFER,
  144. m_cylinder_instance_capacity * sizeof(GL::PrimitiveInstanceGpu),
  145. nullptr, GL_DYNAMIC_DRAW);
  146. setup_instance_attributes(m_cylinder_vao, m_cylinder_instance_buffer);
  147. glBindVertexArray(0);
  148. }
  149. void PrimitiveBatchPipeline::initialize_cone_vao() {
  150. Mesh *unit = getUnitCone();
  151. if (unit == nullptr) {
  152. return;
  153. }
  154. const auto &vertices = unit->getVertices();
  155. const auto &indices = unit->getIndices();
  156. if (vertices.empty() || indices.empty()) {
  157. return;
  158. }
  159. glGenVertexArrays(1, &m_cone_vao);
  160. glBindVertexArray(m_cone_vao);
  161. glGenBuffers(1, &m_cone_vertex_buffer);
  162. glBindBuffer(GL_ARRAY_BUFFER, m_cone_vertex_buffer);
  163. glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex),
  164. vertices.data(), GL_STATIC_DRAW);
  165. glGenBuffers(1, &m_cone_index_buffer);
  166. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_cone_index_buffer);
  167. glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int),
  168. indices.data(), GL_STATIC_DRAW);
  169. m_cone_index_count = static_cast<GLsizei>(indices.size());
  170. glEnableVertexAttribArray(Position);
  171. glVertexAttribPointer(Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  172. reinterpret_cast<void *>(offsetof(Vertex, position)));
  173. glEnableVertexAttribArray(Normal);
  174. glVertexAttribPointer(Normal, Vec3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  175. reinterpret_cast<void *>(offsetof(Vertex, normal)));
  176. glEnableVertexAttribArray(TexCoord);
  177. glVertexAttribPointer(TexCoord, Vec2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
  178. reinterpret_cast<void *>(offsetof(Vertex, tex_coord)));
  179. glGenBuffers(1, &m_cone_instance_buffer);
  180. glBindBuffer(GL_ARRAY_BUFFER, m_cone_instance_buffer);
  181. m_cone_instance_capacity = k_default_instance_capacity;
  182. glBufferData(GL_ARRAY_BUFFER,
  183. m_cone_instance_capacity * sizeof(GL::PrimitiveInstanceGpu),
  184. nullptr, GL_DYNAMIC_DRAW);
  185. setup_instance_attributes(m_cone_vao, m_cone_instance_buffer);
  186. glBindVertexArray(0);
  187. }
  188. void PrimitiveBatchPipeline::shutdown_vaos() {
  189. if (m_sphere_vao != 0) {
  190. glDeleteVertexArrays(1, &m_sphere_vao);
  191. m_sphere_vao = 0;
  192. }
  193. if (m_sphere_vertex_buffer != 0) {
  194. glDeleteBuffers(1, &m_sphere_vertex_buffer);
  195. m_sphere_vertex_buffer = 0;
  196. }
  197. if (m_sphere_index_buffer != 0) {
  198. glDeleteBuffers(1, &m_sphere_index_buffer);
  199. m_sphere_index_buffer = 0;
  200. }
  201. if (m_sphere_instance_buffer != 0) {
  202. glDeleteBuffers(1, &m_sphere_instance_buffer);
  203. m_sphere_instance_buffer = 0;
  204. }
  205. if (m_cylinder_vao != 0) {
  206. glDeleteVertexArrays(1, &m_cylinder_vao);
  207. m_cylinder_vao = 0;
  208. }
  209. if (m_cylinder_vertex_buffer != 0) {
  210. glDeleteBuffers(1, &m_cylinder_vertex_buffer);
  211. m_cylinder_vertex_buffer = 0;
  212. }
  213. if (m_cylinder_index_buffer != 0) {
  214. glDeleteBuffers(1, &m_cylinder_index_buffer);
  215. m_cylinder_index_buffer = 0;
  216. }
  217. if (m_cylinder_instance_buffer != 0) {
  218. glDeleteBuffers(1, &m_cylinder_instance_buffer);
  219. m_cylinder_instance_buffer = 0;
  220. }
  221. if (m_cone_vao != 0) {
  222. glDeleteVertexArrays(1, &m_cone_vao);
  223. m_cone_vao = 0;
  224. }
  225. if (m_cone_vertex_buffer != 0) {
  226. glDeleteBuffers(1, &m_cone_vertex_buffer);
  227. m_cone_vertex_buffer = 0;
  228. }
  229. if (m_cone_index_buffer != 0) {
  230. glDeleteBuffers(1, &m_cone_index_buffer);
  231. m_cone_index_buffer = 0;
  232. }
  233. if (m_cone_instance_buffer != 0) {
  234. glDeleteBuffers(1, &m_cone_instance_buffer);
  235. m_cone_instance_buffer = 0;
  236. }
  237. }
  238. void PrimitiveBatchPipeline::upload_sphere_instances(
  239. const GL::PrimitiveInstanceGpu *data, std::size_t count) {
  240. if (count == 0 || data == nullptr) {
  241. return;
  242. }
  243. glBindBuffer(GL_ARRAY_BUFFER, m_sphere_instance_buffer);
  244. if (count > m_sphere_instance_capacity) {
  245. m_sphere_instance_capacity =
  246. static_cast<std::size_t>(count * k_growth_factor);
  247. glBufferData(GL_ARRAY_BUFFER,
  248. m_sphere_instance_capacity * sizeof(GL::PrimitiveInstanceGpu),
  249. nullptr, GL_DYNAMIC_DRAW);
  250. }
  251. glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(GL::PrimitiveInstanceGpu),
  252. data);
  253. }
  254. void PrimitiveBatchPipeline::upload_cylinder_instances(
  255. const GL::PrimitiveInstanceGpu *data, std::size_t count) {
  256. if (count == 0 || data == nullptr) {
  257. return;
  258. }
  259. glBindBuffer(GL_ARRAY_BUFFER, m_cylinder_instance_buffer);
  260. if (count > m_cylinder_instance_capacity) {
  261. m_cylinder_instance_capacity =
  262. static_cast<std::size_t>(count * k_growth_factor);
  263. glBufferData(GL_ARRAY_BUFFER,
  264. m_cylinder_instance_capacity *
  265. sizeof(GL::PrimitiveInstanceGpu),
  266. nullptr, GL_DYNAMIC_DRAW);
  267. }
  268. glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(GL::PrimitiveInstanceGpu),
  269. data);
  270. }
  271. void PrimitiveBatchPipeline::upload_cone_instances(
  272. const GL::PrimitiveInstanceGpu *data, std::size_t count) {
  273. if (count == 0 || data == nullptr) {
  274. return;
  275. }
  276. glBindBuffer(GL_ARRAY_BUFFER, m_cone_instance_buffer);
  277. if (count > m_cone_instance_capacity) {
  278. m_cone_instance_capacity =
  279. static_cast<std::size_t>(count * k_growth_factor);
  280. glBufferData(GL_ARRAY_BUFFER,
  281. m_cone_instance_capacity * sizeof(GL::PrimitiveInstanceGpu),
  282. nullptr, GL_DYNAMIC_DRAW);
  283. }
  284. glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(GL::PrimitiveInstanceGpu),
  285. data);
  286. }
  287. void PrimitiveBatchPipeline::draw_spheres(std::size_t count,
  288. const QMatrix4x4 &view_proj) {
  289. if (count == 0 || m_sphere_vao == 0 || m_shader == nullptr) {
  290. return;
  291. }
  292. m_shader->use();
  293. m_shader->setUniform(m_uniforms.view_proj, view_proj);
  294. m_shader->setUniform(m_uniforms.light_dir, QVector3D(0.35F, 0.8F, 0.45F));
  295. m_shader->setUniform(m_uniforms.ambient_strength, 0.3F);
  296. glBindVertexArray(m_sphere_vao);
  297. glDrawElementsInstanced(GL_TRIANGLES, m_sphere_index_count, GL_UNSIGNED_INT,
  298. nullptr, static_cast<GLsizei>(count));
  299. glBindVertexArray(0);
  300. }
  301. void PrimitiveBatchPipeline::draw_cylinders(std::size_t count,
  302. const QMatrix4x4 &view_proj) {
  303. if (count == 0 || m_cylinder_vao == 0 || m_shader == nullptr) {
  304. return;
  305. }
  306. m_shader->use();
  307. m_shader->setUniform(m_uniforms.view_proj, view_proj);
  308. m_shader->setUniform(m_uniforms.light_dir, QVector3D(0.35F, 0.8F, 0.45F));
  309. m_shader->setUniform(m_uniforms.ambient_strength, 0.3F);
  310. glBindVertexArray(m_cylinder_vao);
  311. glDrawElementsInstanced(GL_TRIANGLES, m_cylinder_index_count, GL_UNSIGNED_INT,
  312. nullptr, static_cast<GLsizei>(count));
  313. glBindVertexArray(0);
  314. }
  315. void PrimitiveBatchPipeline::draw_cones(std::size_t count,
  316. const QMatrix4x4 &view_proj) {
  317. if (count == 0 || m_cone_vao == 0 || m_shader == nullptr) {
  318. return;
  319. }
  320. m_shader->use();
  321. m_shader->setUniform(m_uniforms.view_proj, view_proj);
  322. m_shader->setUniform(m_uniforms.light_dir, QVector3D(0.35F, 0.8F, 0.45F));
  323. m_shader->setUniform(m_uniforms.ambient_strength, 0.3F);
  324. glBindVertexArray(m_cone_vao);
  325. glDrawElementsInstanced(GL_TRIANGLES, m_cone_index_count, GL_UNSIGNED_INT,
  326. nullptr, static_cast<GLsizei>(count));
  327. glBindVertexArray(0);
  328. }
  329. } // namespace Render::GL::BackendPipelines