persistent_buffer.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #pragma once
  2. #include <QDebug>
  3. #include <QOpenGLContext>
  4. #include <QOpenGLExtraFunctions>
  5. #include <cstddef>
  6. #include <cstring>
  7. namespace Render::GL {
  8. template <typename T>
  9. class PersistentRingBuffer : protected QOpenGLExtraFunctions {
  10. public:
  11. PersistentRingBuffer() = default;
  12. ~PersistentRingBuffer() { destroy(); }
  13. PersistentRingBuffer(const PersistentRingBuffer &) = delete;
  14. PersistentRingBuffer &operator=(const PersistentRingBuffer &) = delete;
  15. bool initialize(std::size_t capacity, int buffersInFlight = 3) {
  16. if (m_buffer != 0)
  17. return false;
  18. initializeOpenGLFunctions();
  19. if (!hasOpenGLFeature(QOpenGLFunctions::Buffers)) {
  20. return false;
  21. }
  22. m_capacity = capacity;
  23. m_buffersInFlight = buffersInFlight;
  24. m_totalSize = capacity * sizeof(T) * buffersInFlight;
  25. m_currentFrame = 0;
  26. m_frameOffset = 0;
  27. glGenBuffers(1, &m_buffer);
  28. glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
  29. const GLbitfield storageFlags = 0x0100;
  30. const GLbitfield mapFlags = 0x0002 | 0x0040 | 0x0080;
  31. QOpenGLContext *ctx = QOpenGLContext::currentContext();
  32. if (!ctx) {
  33. qWarning() << "PersistentRingBuffer: No current OpenGL context";
  34. glBindBuffer(GL_ARRAY_BUFFER, 0);
  35. glDeleteBuffers(1, &m_buffer);
  36. m_buffer = 0;
  37. return false;
  38. }
  39. typedef void(QOPENGLF_APIENTRYP type_glBufferStorage)(
  40. GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
  41. type_glBufferStorage glBufferStorage =
  42. reinterpret_cast<type_glBufferStorage>(
  43. ctx->getProcAddress("glBufferStorage"));
  44. if (!glBufferStorage) {
  45. glBindBuffer(GL_ARRAY_BUFFER, 0);
  46. glDeleteBuffers(1, &m_buffer);
  47. m_buffer = 0;
  48. return false;
  49. }
  50. glBufferStorage(GL_ARRAY_BUFFER, m_totalSize, nullptr,
  51. storageFlags | mapFlags);
  52. GLenum err = glGetError();
  53. if (err != GL_NO_ERROR) {
  54. qWarning() << "PersistentRingBuffer: glBufferStorage failed with error:"
  55. << err;
  56. glBindBuffer(GL_ARRAY_BUFFER, 0);
  57. glDeleteBuffers(1, &m_buffer);
  58. m_buffer = 0;
  59. return false;
  60. }
  61. m_mappedPtr = glMapBufferRange(GL_ARRAY_BUFFER, 0, m_totalSize, mapFlags);
  62. glBindBuffer(GL_ARRAY_BUFFER, 0);
  63. if (!m_mappedPtr) {
  64. qWarning() << "PersistentRingBuffer: glMapBufferRange failed";
  65. destroy();
  66. return false;
  67. }
  68. return true;
  69. }
  70. void destroy() {
  71. if (m_buffer == 0)
  72. return;
  73. initializeOpenGLFunctions();
  74. if (m_mappedPtr) {
  75. glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
  76. glUnmapBuffer(GL_ARRAY_BUFFER);
  77. glBindBuffer(GL_ARRAY_BUFFER, 0);
  78. m_mappedPtr = nullptr;
  79. }
  80. glDeleteBuffers(1, &m_buffer);
  81. m_buffer = 0;
  82. m_capacity = 0;
  83. m_totalSize = 0;
  84. }
  85. void beginFrame() {
  86. m_currentFrame = (m_currentFrame + 1) % m_buffersInFlight;
  87. m_frameOffset = m_currentFrame * m_capacity * sizeof(T);
  88. m_currentCount = 0;
  89. }
  90. std::size_t write(const T *data, std::size_t count) {
  91. if (!m_mappedPtr || count == 0 || count > m_capacity)
  92. return 0;
  93. std::size_t writeOffset = m_frameOffset + m_currentCount * sizeof(T);
  94. void *dest = static_cast<char *>(m_mappedPtr) + writeOffset;
  95. std::memcpy(dest, data, count * sizeof(T));
  96. std::size_t elementOffset = m_currentCount;
  97. m_currentCount += count;
  98. return elementOffset;
  99. }
  100. GLuint buffer() const { return m_buffer; }
  101. std::size_t currentOffset() const { return m_frameOffset; }
  102. std::size_t capacity() const { return m_capacity; }
  103. std::size_t count() const { return m_currentCount; }
  104. bool isValid() const { return m_buffer != 0 && m_mappedPtr != nullptr; }
  105. private:
  106. GLuint m_buffer = 0;
  107. void *m_mappedPtr = nullptr;
  108. std::size_t m_capacity = 0;
  109. std::size_t m_totalSize = 0;
  110. std::size_t m_frameOffset = 0;
  111. std::size_t m_currentCount = 0;
  112. int m_buffersInFlight = 3;
  113. int m_currentFrame = 0;
  114. };
  115. } // namespace Render::GL