gl_surface.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "ui/gl/gl_surface.h"
  8. #include "ui/rp_widget.h"
  9. #include "ui/painter.h"
  10. #include <QtCore/QCoreApplication>
  11. #include <QtGui/QtEvents>
  12. #include <QtGui/QOpenGLContext>
  13. #include <QtGui/QWindow>
  14. #include <QOpenGLWidget>
  15. namespace Ui::GL {
  16. namespace {
  17. struct SurfaceTraits : RpWidgetDefaultTraits {
  18. static constexpr bool kSetZeroGeometry = false;
  19. };
  20. class SurfaceOpenGL final
  21. : public RpWidgetBase<QOpenGLWidget, SurfaceTraits> {
  22. public:
  23. SurfaceOpenGL(QWidget *parent, std::unique_ptr<Renderer> renderer);
  24. ~SurfaceOpenGL();
  25. private:
  26. void initializeGL() override;
  27. void resizeEvent(QResizeEvent *e) override;
  28. void resizeGL(int w, int h) override;
  29. void paintEvent(QPaintEvent *e) override;
  30. void paintGL() override;
  31. bool eventHook(QEvent *e) override;
  32. void callDeInit();
  33. const std::unique_ptr<Renderer> _renderer;
  34. QMetaObject::Connection _connection;
  35. QSize _deviceSize;
  36. };
  37. class SurfaceRaster final : public RpWidgetBase<QWidget, SurfaceTraits> {
  38. public:
  39. SurfaceRaster(QWidget *parent, std::unique_ptr<Renderer> renderer);
  40. private:
  41. void paintEvent(QPaintEvent *e) override;
  42. const std::unique_ptr<Renderer> _renderer;
  43. };
  44. SurfaceOpenGL::SurfaceOpenGL(
  45. QWidget *parent,
  46. std::unique_ptr<Renderer> renderer)
  47. : RpWidgetBase<QOpenGLWidget, SurfaceTraits>(parent)
  48. , _renderer(std::move(renderer)) {
  49. setUpdateBehavior(QOpenGLWidget::PartialUpdate);
  50. }
  51. SurfaceOpenGL::~SurfaceOpenGL() {
  52. callDeInit();
  53. }
  54. void SurfaceOpenGL::initializeGL() {
  55. if (_connection) {
  56. QObject::disconnect(base::take(_connection));
  57. }
  58. const auto context = this->context();
  59. _connection = QObject::connect(
  60. context,
  61. &QOpenGLContext::aboutToBeDestroyed,
  62. [=] { callDeInit(); });
  63. _renderer->init(this, *context->functions());
  64. }
  65. void SurfaceOpenGL::resizeEvent(QResizeEvent *e) {
  66. if (!window()->windowHandle()) {
  67. return;
  68. }
  69. QOpenGLWidget::resizeEvent(e);
  70. }
  71. void SurfaceOpenGL::resizeGL(int w, int h) {
  72. _deviceSize = QSize(w, h) * devicePixelRatio();
  73. _renderer->resize(this, *context()->functions(), w, h);
  74. }
  75. void SurfaceOpenGL::paintEvent(QPaintEvent *e) {
  76. if (_deviceSize != size() * devicePixelRatio()) {
  77. QCoreApplication::postEvent(this, new QResizeEvent(size(), size()));
  78. }
  79. QOpenGLWidget::paintEvent(e);
  80. }
  81. void SurfaceOpenGL::paintGL() {
  82. if (!updatesEnabled() || size().isEmpty() || !isValid()) {
  83. return;
  84. }
  85. const auto f = context()->functions();
  86. if (const auto bg = _renderer->clearColor()) {
  87. f->glClearColor(bg->redF(), bg->greenF(), bg->blueF(), bg->alphaF());
  88. f->glClear(GL_COLOR_BUFFER_BIT);
  89. }
  90. f->glDisable(GL_BLEND);
  91. _renderer->paint(this, *f);
  92. }
  93. bool SurfaceOpenGL::eventHook(QEvent *e) {
  94. const auto result = RpWidgetBase::eventHook(e);
  95. if (e->type() == QEvent::ScreenChangeInternal) {
  96. _deviceSize = size() * devicePixelRatio();
  97. }
  98. return result;
  99. }
  100. void SurfaceOpenGL::callDeInit() {
  101. if (!_connection) {
  102. return;
  103. }
  104. QObject::disconnect(base::take(_connection));
  105. makeCurrent();
  106. const auto context = this->context();
  107. _renderer->deinit(
  108. this,
  109. ((isValid() && context && QOpenGLContext::currentContext() == context)
  110. ? context->functions()
  111. : nullptr));
  112. }
  113. SurfaceRaster::SurfaceRaster(
  114. QWidget *parent,
  115. std::unique_ptr<Renderer> renderer)
  116. : RpWidgetBase<QWidget, SurfaceTraits>(parent)
  117. , _renderer(std::move(renderer)) {
  118. }
  119. void SurfaceRaster::paintEvent(QPaintEvent *e) {
  120. _renderer->paintFallback(Painter(this), e->region(), Backend::Raster);
  121. }
  122. } // namespace
  123. void Renderer::paint(
  124. not_null<QOpenGLWidget*> widget,
  125. QOpenGLFunctions &f) {
  126. paintFallback(Painter(widget.get()), widget->rect(), Backend::OpenGL);
  127. }
  128. std::unique_ptr<RpWidgetWrap> CreateSurface(
  129. Fn<ChosenRenderer(Capabilities)> chooseRenderer) {
  130. auto chosen = chooseRenderer(CheckCapabilities(nullptr));
  131. switch (chosen.backend) {
  132. case Backend::OpenGL:
  133. return std::make_unique<SurfaceOpenGL>(
  134. nullptr,
  135. std::move(chosen.renderer));
  136. case Backend::Raster:
  137. return std::make_unique<SurfaceRaster>(
  138. nullptr,
  139. std::move(chosen.renderer));
  140. }
  141. Unexpected("Backend value in Ui::GL::CreateSurface.");
  142. }
  143. std::unique_ptr<RpWidgetWrap> CreateSurface(
  144. QWidget *parent,
  145. ChosenRenderer chosen) {
  146. switch (chosen.backend) {
  147. case Backend::OpenGL:
  148. return std::make_unique<SurfaceOpenGL>(
  149. parent,
  150. std::move(chosen.renderer));
  151. case Backend::Raster:
  152. return std::make_unique<SurfaceRaster>(
  153. parent,
  154. std::move(chosen.renderer));
  155. }
  156. Unexpected("Backend value in Ui::GL::CreateSurface.");
  157. }
  158. } // namespace Ui::GL