platform_gl.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #pragma once
  2. #include <QDebug>
  3. #include <QOpenGLContext>
  4. #include <QOpenGLExtraFunctions>
  5. namespace Render::GL::Platform {
  6. inline auto supportsPersistentMapping() -> bool {
  7. auto *ctx = QOpenGLContext::currentContext();
  8. if (ctx == nullptr) {
  9. return false;
  10. }
  11. const auto glVersion = ctx->format().version();
  12. const int majorVersion = glVersion.first;
  13. const int minorVersion = glVersion.second;
  14. if (majorVersion > 4 || (majorVersion == 4 && minorVersion >= 4)) {
  15. return true;
  16. }
  17. const auto extensions = QString::fromLatin1(reinterpret_cast<const char *>(
  18. ctx->extraFunctions()->glGetString(GL_EXTENSIONS)));
  19. return extensions.contains("GL_ARB_buffer_storage");
  20. }
  21. inline auto getBufferStorageFunction() -> void * {
  22. auto *ctx = QOpenGLContext::currentContext();
  23. if (ctx == nullptr) {
  24. return nullptr;
  25. }
  26. void *func = reinterpret_cast<void *>(ctx->getProcAddress("glBufferStorage"));
  27. if (func == nullptr) {
  28. func = reinterpret_cast<void *>(ctx->getProcAddress("glBufferStorageARB"));
  29. }
  30. #ifdef Q_OS_WIN
  31. if (func == nullptr) {
  32. qWarning() << "Platform::getBufferStorageFunction: glBufferStorage not "
  33. "available on Windows";
  34. }
  35. #endif
  36. return func;
  37. }
  38. #ifndef GL_MAP_PERSISTENT_BIT
  39. #define GL_MAP_PERSISTENT_BIT 0x0040
  40. #endif
  41. #ifndef GL_MAP_COHERENT_BIT
  42. #define GL_MAP_COHERENT_BIT 0x0080
  43. #endif
  44. #ifndef GL_MAP_WRITE_BIT
  45. #define GL_MAP_WRITE_BIT 0x0002
  46. #endif
  47. #ifndef GL_DYNAMIC_STORAGE_BIT
  48. #define GL_DYNAMIC_STORAGE_BIT 0x0100
  49. #endif
  50. class BufferStorageHelper {
  51. public:
  52. enum class Mode { Persistent, Fallback };
  53. static auto createBuffer(GLuint buffer, GLsizeiptr size,
  54. Mode *outMode) -> bool {
  55. if (supportsPersistentMapping()) {
  56. typedef void(QOPENGLF_APIENTRYP type_glBufferStorage)(
  57. GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
  58. auto glBufferStorage =
  59. reinterpret_cast<type_glBufferStorage>(getBufferStorageFunction());
  60. if (glBufferStorage != nullptr) {
  61. const GLbitfield storageFlags = GL_DYNAMIC_STORAGE_BIT;
  62. const GLbitfield mapFlags =
  63. GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
  64. glBufferStorage(GL_ARRAY_BUFFER, size, nullptr,
  65. storageFlags | mapFlags);
  66. GLenum const err =
  67. QOpenGLContext::currentContext()->extraFunctions()->glGetError();
  68. if (err == GL_NO_ERROR) {
  69. if (outMode != nullptr) {
  70. *outMode = Mode::Persistent;
  71. }
  72. return true;
  73. }
  74. qWarning() << "BufferStorageHelper: glBufferStorage failed with error:"
  75. << err;
  76. }
  77. }
  78. qInfo() << "BufferStorageHelper: Using fallback buffer mode (glBufferData)";
  79. QOpenGLContext::currentContext()->extraFunctions()->glBufferData(
  80. GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
  81. if (outMode != nullptr) {
  82. *outMode = Mode::Fallback;
  83. }
  84. return true;
  85. }
  86. static auto mapBuffer(GLsizeiptr size, Mode mode) -> void * {
  87. auto *gl = QOpenGLContext::currentContext()->extraFunctions();
  88. if (mode == Mode::Persistent) {
  89. const GLbitfield mapFlags =
  90. GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
  91. void *ptr = gl->glMapBufferRange(GL_ARRAY_BUFFER, 0, size, mapFlags);
  92. if (ptr != nullptr) {
  93. return ptr;
  94. }
  95. qWarning()
  96. << "BufferStorageHelper: Persistent mapping failed, falling back";
  97. }
  98. return gl->glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT);
  99. }
  100. };
  101. } // namespace Render::GL::Platform