MythTV  master
mythpainteropengl.cpp
Go to the documentation of this file.
1 // C++
2 #include <algorithm>
3 
4 // Qt
5 #include <QtGlobal>
6 #include <QCoreApplication>
7 #include <QPainter>
8 
9 // MythTV
10 #include "mythmainwindow.h"
11 #include "mythrenderopengl.h"
12 #include "mythpainteropengl.h"
13 
15  : MythPainterGPU(Parent),
16  m_render(Render)
17 {
19 
20  if (!m_render)
21  LOG(VB_GENERAL, LOG_ERR, "OpenGL painter has no render device");
22 }
23 
25 {
26  if (!m_render)
27  return;
28  if (!m_render->IsReady())
29  return;
30  OpenGLLocker locker(m_render);
31  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
32  m_render->logDebugMarker("PAINTER_RELEASE_START");
33  Teardown();
35  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
36  m_render->logDebugMarker("PAINTER_RELEASE_END");
37 }
38 
40 {
41  OpenGLLocker locker(m_render);
42  ClearCache();
45  {
46  for (auto & buf : m_mappedBufferPool)
47  {
48  delete buf;
49  buf = nullptr;
50  }
52  }
53  for (auto * proc : qAsConst(m_procedurals))
54  delete proc;
55  m_procedurals.clear();
57 }
58 
60 {
61  if (!m_render || m_textureDeleteList.empty())
62  return;
63 
64  QMutexLocker gllocker(&m_imageAndTextureLock);
65  OpenGLLocker locker(m_render);
66  while (!m_textureDeleteList.empty())
67  {
68  MythGLTexture *texture = m_textureDeleteList.front();
70  m_render->DeleteTexture(texture);
71  m_textureDeleteList.pop_front();
72  }
73 }
74 
76 {
77  LOG(VB_GENERAL, LOG_INFO, "Clearing OpenGL painter cache.");
78 
79  QMutexLocker locker(&m_imageAndTextureLock);
80  QMapIterator<MythImage *, MythGLTexture*> it(m_imageToTextureMap);
81  while (it.hasNext())
82  {
83  it.next();
84  m_textureDeleteList.push_back(m_imageToTextureMap[it.key()]);
85  m_imageExpireList.remove(it.key());
86  }
87  m_imageToTextureMap.clear();
88 }
89 
90 void MythOpenGLPainter::Begin(QPaintDevice *Parent)
91 {
92  MythPainterGPU::Begin(Parent);
93 
94  m_frameTime = QTime::currentTime().msecsSinceStartOfDay();
95  if (!(m_render && m_parent))
96  {
97  LOG(VB_GENERAL, LOG_ERR, "FATAL ERROR: No render device in 'Begin'");
98  return;
99  }
100 
102  {
104  // initialise the VBO pool
105  std::generate(m_mappedBufferPool.begin(), m_mappedBufferPool.end(),
106  [&]() { return m_render->CreateVBO(static_cast<int>(MythRenderOpenGL::kVertexSize)); });
107  }
108 
109  QSize currentsize = m_parent->size();
110 
111  // check if we need to adjust cache sizes
112  // NOTE - don't use the scaled size if using high DPI. Our images are at the lower
113  // resolution
114  if (m_lastSize != currentsize)
115  {
116  // This will scale the cache depending on the resolution in use
117  static const int s_onehd = 1920 * 1080;
118  static const int s_basesize = 64;
119  m_lastSize = currentsize;
120  float hdscreens = (static_cast<float>(m_lastSize.width() + 1) * m_lastSize.height()) / s_onehd;
121  int cpu = std::max(static_cast<int>(hdscreens * s_basesize), s_basesize);
122  int gpu = cpu * 3 / 2;
123  SetMaximumCacheSizes(gpu, cpu);
124  }
125 
126  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
127  m_render->logDebugMarker("PAINTER_FRAME_START");
128 
129  DeleteTextures();
131 
132  // If master (have complete swap control) then bind default framebuffer and clear
133  if (m_viewControl.testFlag(Framebuffer))
134  {
135  m_render->BindFramebuffer(nullptr);
136  m_render->SetBackground(0, 0, 0, 255);
138  }
139 
140  // If we have viewport control, set as needed.
141  if (m_viewControl.testFlag(Viewport))
142  {
143  // If using high DPI then scale the viewport
144  if (m_usingHighDPI)
145  currentsize *= m_pixelRatio;
146  m_render->SetViewPort(QRect(0, 0, currentsize.width(), currentsize.height()));
147  }
148 }
149 
151 {
152  if (!m_render)
153  {
154  LOG(VB_GENERAL, LOG_ERR, "FATAL ERROR: No render device in 'End'");
155  return;
156  }
157 
158  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
159  m_render->logDebugMarker("PAINTER_FRAME_END");
160 
161  if (m_viewControl.testFlag(Framebuffer))
162  {
163  m_render->Flush();
165  }
167 
168  m_mappedTextures.clear();
170 }
171 
173 {
174  if (!m_render)
175  return nullptr;
176 
177  QMutexLocker locker(&m_imageAndTextureLock);
178  if (m_imageToTextureMap.contains(Image))
179  {
180  if (!Image->IsChanged())
181  {
182  m_imageExpireList.remove(Image);
183  m_imageExpireList.push_back(Image);
184  return m_imageToTextureMap[Image];
185  }
186  DeleteFormatImagePriv(Image);
187  }
188  locker.unlock();
189 
190  Image->SetChanged(false);
191 
192  int count = 0;
193  MythGLTexture* texture = nullptr;
194  while (texture == nullptr)
195  {
196  texture = m_render->CreateTextureFromQImage(Image);
197  if (texture != nullptr)
198  break;
199 
200  // This can happen if the cached textures are too big for GPU memory
201  if ((count++ > 1000) || (m_hardwareCacheSize <= 8 * 1024 * 1024))
202  {
203  LOG(VB_GENERAL, LOG_ERR, "Failed to create OpenGL texture.");
204  return nullptr;
205  }
206 
207  // Shrink the cache size
209  LOG(VB_GENERAL, LOG_NOTICE, QString("Shrinking UIPainterMaxCacheHW to %1KB")
210  .arg(m_maxHardwareCacheSize / 1024));
211 
212  locker.relock();
214  {
215  MythImage *expiredIm = m_imageExpireList.front();
216  m_imageExpireList.pop_front();
217  DeleteFormatImagePriv(expiredIm);
218  DeleteTextures();
219  }
220  locker.unlock();
221  }
222 
223  CheckFormatImage(Image);
225  locker.relock();
226  m_imageToTextureMap[Image] = texture;
227  m_imageExpireList.push_back(Image);
228 
230  {
231  MythImage *expiredIm = m_imageExpireList.front();
232  m_imageExpireList.pop_front();
233  DeleteFormatImagePriv(expiredIm);
234  DeleteTextures();
235  }
236 
237  return texture;
238 }
239 
240 #ifdef Q_OS_MACOS
241 #define DEST dest
242 #else
243 #define DEST Dest
244 #endif
245 
246 void MythOpenGLPainter::DrawImage(const QRect Dest, MythImage *Image,
247  const QRect Source, int Alpha)
248 {
249  if (m_render)
250  {
251  qreal pixelratio = 1.0;
252  if (m_usingHighDPI && m_viewControl.testFlag(Viewport))
253  pixelratio = m_pixelRatio;
254 #ifdef Q_OS_MACOS
255  QRect dest = QRect(static_cast<int>(Dest.left() * pixelratio),
256  static_cast<int>(Dest.top() * pixelratio),
257  static_cast<int>(Dest.width() * pixelratio),
258  static_cast<int>(Dest.height() * pixelratio));
259 #endif
260 
261  // Drawing an image multiple times with the same VBO will stall most GPUs as
262  // the VBO is re-mapped whilst still in use. Use a pooled VBO instead.
263  MythGLTexture *texture = GetTextureFromCache(Image);
264  if (texture && m_mappedTextures.contains(texture))
265  {
266  QOpenGLBuffer *vbo = texture->m_vbo;
268  texture->m_destination = QRect();
269  m_render->DrawBitmap(texture, nullptr, Source, DEST, nullptr, Alpha, pixelratio);
270  texture->m_destination = QRect();
271  texture->m_vbo = vbo;
274  }
275  else
276  {
277  m_render->DrawBitmap(texture, nullptr, Source, DEST, nullptr, Alpha, pixelratio);
278  m_mappedTextures.append(texture);
279  }
280  }
281 }
282 
283 void MythOpenGLPainter::DrawProcedural(QRect Dest, int Alpha, const ProcSource& VertexSource, const ProcSource& FragmentSource, const QString &SourceHash)
284 {
285  if (auto * shader = GetProceduralShader(VertexSource, FragmentSource, SourceHash); shader && m_render)
286  m_render->DrawProcedural(Dest, Alpha, nullptr, shader, m_frameTime);
287 }
288 
289 QOpenGLShaderProgram* MythOpenGLPainter::GetProceduralShader(const ProcSource& VertexSource, const ProcSource& FragmentSource, const QString& SourceHash)
290 {
291  if (!m_render)
292  return nullptr;
293 
294  if (auto program = m_procedurals.find(SourceHash); program != m_procedurals.end())
295  return *program;
296 
297  auto * result = m_render->CreateShaderProgram(QString(*VertexSource), QString(*FragmentSource));
298  m_procedurals.insert(SourceHash, result);
299  LOG(VB_GENERAL, LOG_INFO, QString("%1 procedural shaders cached").arg(m_procedurals.size()));
300  return result;
301 }
302 
312 void MythOpenGLPainter::DrawRect(const QRect Area, const QBrush &FillBrush,
313  const QPen &LinePen, int Alpha)
314 {
315  if ((FillBrush.style() == Qt::SolidPattern ||
316  FillBrush.style() == Qt::NoBrush) && m_render && !m_usingHighDPI)
317  {
318  m_render->DrawRect(nullptr, Area, FillBrush, LinePen, Alpha);
319  return;
320  }
321  MythPainterGPU::DrawRect(Area, FillBrush, LinePen, Alpha);
322 }
323 
324 void MythOpenGLPainter::DrawRoundRect(const QRect Area, int CornerRadius,
325  const QBrush &FillBrush,
326  const QPen &LinePen, int Alpha)
327 {
328  if ((FillBrush.style() == Qt::SolidPattern ||
329  FillBrush.style() == Qt::NoBrush) && m_render && !m_usingHighDPI)
330  {
331  m_render->DrawRoundRect(nullptr, Area, CornerRadius, FillBrush,
332  LinePen, Alpha);
333  return;
334  }
335  MythPainterGPU::DrawRoundRect(Area, CornerRadius, FillBrush, LinePen, Alpha);
336 }
337 
339 {
340  QMutexLocker locker(&m_imageAndTextureLock);
341  if (m_imageToTextureMap.contains(Image))
342  {
343  m_textureDeleteList.push_back(m_imageToTextureMap[Image]);
344  m_imageToTextureMap.remove(Image);
345  m_imageExpireList.remove(Image);
346  }
347 }
348 
349 void MythOpenGLPainter::PushTransformation(const UIEffects &Fx, QPointF Center)
350 {
351  if (m_render)
352  m_render->PushTransformation(Fx, Center);
353 }
354 
356 {
357  if (m_render)
359 }
MythOpenGLPainter::m_imageExpireList
std::list< MythImage * > m_imageExpireList
Definition: mythpainteropengl.h:72
MythPainterGPU::m_parent
MythMainWindow * m_parent
Definition: mythpaintergpu.h:33
build_compdb.dest
dest
Definition: build_compdb.py:9
MythOpenGLPainter::DeleteTextures
void DeleteTextures(void)
Definition: mythpainteropengl.cpp:59
MythGLTexture
Definition: mythrenderopengl.h:60
MythPainter::m_hardwareCacheSize
int m_hardwareCacheSize
Definition: mythpainter.h:135
MythRenderOpenGL::SetBackground
void SetBackground(uint8_t Red, uint8_t Green, uint8_t Blue, uint8_t Alpha)
Definition: mythrenderopengl.cpp:618
MythRenderOpenGL::IsReady
bool IsReady(void)
Definition: mythrenderopengl.cpp:506
MythGLTexture::m_destination
QRect m_destination
Definition: mythrenderopengl.h:79
MythRenderOpenGL::ClearFramebuffer
void ClearFramebuffer(void)
Definition: mythrenderopengl.cpp:805
MythOpenGLPainter::Begin
void Begin(QPaintDevice *Parent) override
Definition: mythpainteropengl.cpp:90
MythPainter::SetMaximumCacheSizes
void SetMaximumCacheSizes(int hardware, int software)
Definition: mythpainter.cpp:607
MythOpenGLPainter::m_imageAndTextureLock
QRecursiveMutex m_imageAndTextureLock
Definition: mythpainteropengl.h:69
MythOpenGLPainter::MythOpenGLPainter
MythOpenGLPainter(MythRenderOpenGL *Render, MythMainWindow *Parent)
Definition: mythpainteropengl.cpp:14
MythOpenGLPainter::DrawRect
void DrawRect(QRect Area, const QBrush &FillBrush, const QPen &LinePen, int Alpha) override
Draw a rectangle.
Definition: mythpainteropengl.cpp:312
MAX_BUFFER_POOL
static constexpr size_t MAX_BUFFER_POOL
Definition: mythpainteropengl.h:26
MythRenderOpenGL::logDebugMarker
void logDebugMarker(const QString &Message)
Definition: mythrenderopengl.cpp:193
MythOpenGLPainter::FreeResources
void FreeResources(void) override
Definition: mythpainteropengl.cpp:39
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
DEST
#define DEST
Definition: mythpainteropengl.cpp:241
MythOpenGLPainter::GetProceduralShader
QOpenGLShaderProgram * GetProceduralShader(const ProcSource &VertexSource, const ProcSource &FragmentSource, const QString &SourceHash)
Definition: mythpainteropengl.cpp:289
MythRenderOpenGL::PushTransformation
void PushTransformation(const UIEffects &Fx, QPointF &Center)
Definition: mythrenderopengl.cpp:1383
MythOpenGLPainter::m_mappedBufferPoolIdx
size_t m_mappedBufferPoolIdx
Definition: mythpainteropengl.h:77
MythRenderOpenGL::DrawBitmap
void DrawBitmap(MythGLTexture *Texture, QOpenGLFramebufferObject *Target, QRect Source, QRect Destination, QOpenGLShaderProgram *Program, int Alpha=255, qreal Scale=1.0)
Definition: mythrenderopengl.cpp:833
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythOpenGLPainter::GetTextureFromCache
MythGLTexture * GetTextureFromCache(MythImage *Image)
Definition: mythpainteropengl.cpp:172
MythPainter::DrawRect
virtual void DrawRect(QRect area, const QBrush &fillBrush, const QPen &linePen, int alpha)
Definition: mythpainter.cpp:157
MythPainter::m_maxHardwareCacheSize
int m_maxHardwareCacheSize
Definition: mythpainter.h:136
MythOpenGLPainter::DrawProcedural
void DrawProcedural(QRect Dest, int Alpha, const ProcSource &VertexSource, const ProcSource &FragmentSource, const QString &SourceHash) override
Definition: mythpainteropengl.cpp:283
MythPainterGPU::m_viewControl
ViewControls m_viewControl
Definition: mythpaintergpu.h:34
MythPainterGPU::m_usingHighDPI
bool m_usingHighDPI
Definition: mythpaintergpu.h:36
MythRenderOpenGL::GetTextureDataSize
static int GetTextureDataSize(MythGLTexture *Texture)
Definition: mythrenderopengl.cpp:672
MythPainter::m_frameTime
float m_frameTime
Definition: mythpainter.h:133
MythOpenGLPainter::PushTransformation
void PushTransformation(const UIEffects &Fx, QPointF Center=QPointF()) override
Definition: mythpainteropengl.cpp:349
mythrenderopengl.h
MythPainterGPU::m_pixelRatio
qreal m_pixelRatio
Definition: mythpaintergpu.h:35
Source
Definition: channelsettings.cpp:69
MythGLTexture::m_vbo
QOpenGLBuffer * m_vbo
Definition: mythrenderopengl.h:73
MythRenderOpenGL::CreateTextureFromQImage
MythGLTexture * CreateTextureFromQImage(QImage *Image)
Definition: mythrenderopengl.cpp:630
MythRenderOpenGL::DrawRect
void DrawRect(QOpenGLFramebufferObject *Target, QRect Area, const QBrush &FillBrush, const QPen &LinePen, int Alpha)
Definition: mythrenderopengl.cpp:979
MythRenderOpenGL::Flush
void Flush(void)
Definition: mythrenderopengl.cpp:597
MythOpenGLPainter::m_render
MythRenderOpenGL * m_render
Definition: mythpainteropengl.h:64
MythPainterGPU::Viewport
@ Viewport
Definition: mythpaintergpu.h:19
MythRenderOpenGL::PopTransformation
void PopTransformation(void)
Definition: mythrenderopengl.cpp:1396
MythRenderOpenGL::swapBuffers
void swapBuffers()
Definition: mythrenderopengl.cpp:511
MythRenderOpenGL::makeCurrent
void makeCurrent()
Definition: mythrenderopengl.cpp:566
MythOpenGLPainter::m_mappedBufferPoolReady
bool m_mappedBufferPoolReady
Definition: mythpainteropengl.h:78
MythRenderOpenGL::DeleteTexture
void DeleteTexture(MythGLTexture *Texture)
Definition: mythrenderopengl.cpp:716
MythOpenGLPainter::DeleteFormatImagePriv
void DeleteFormatImagePriv(MythImage *Image) override
Definition: mythpainteropengl.cpp:338
MythRenderOpenGL::DrawProcedural
void DrawProcedural(QRect Area, int Alpha, QOpenGLFramebufferObject *Target, QOpenGLShaderProgram *Program, float TimeVal)
Definition: mythrenderopengl.cpp:812
MythOpenGLPainter::m_mappedBufferPool
std::array< QOpenGLBuffer *, MAX_BUFFER_POOL > m_mappedBufferPool
Definition: mythpainteropengl.h:76
MythRenderOpenGL::DrawRoundRect
void DrawRoundRect(QOpenGLFramebufferObject *Target, QRect Area, int CornerRadius, const QBrush &FillBrush, const QPen &LinePen, int Alpha)
Definition: mythrenderopengl.cpp:987
MythImage::SetChanged
virtual void SetChanged(bool change=true)
Definition: mythimage.h:50
MythOpenGLPainter::PopTransformation
void PopTransformation(void) override
Definition: mythpainteropengl.cpp:355
MythPainter::FreeResources
virtual void FreeResources(void)
Definition: mythpainter.h:53
MythOpenGLPainter::m_procedurals
QHash< QString, QOpenGLShaderProgram * > m_procedurals
Definition: mythpainteropengl.h:80
MythPainter::End
virtual void End()
Definition: mythpainter.h:55
MythRenderOpenGL::doneCurrent
void doneCurrent()
Definition: mythrenderopengl.cpp:574
mythpainteropengl.h
MythRenderOpenGL
Definition: mythrenderopengl.h:100
ProcSource
std::shared_ptr< QByteArray > ProcSource
Definition: mythpainter.h:32
MythRenderOpenGL::BindFramebuffer
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:785
MythPainterGPU::Framebuffer
@ Framebuffer
Definition: mythpaintergpu.h:20
MythOpenGLPainter::m_mappedTextures
QVector< MythGLTexture * > m_mappedTextures
Definition: mythpainteropengl.h:75
MythImage
Definition: mythimage.h:36
MythPainterGPU::m_lastSize
QSize m_lastSize
Definition: mythpaintergpu.h:37
UIEffects
Definition: mythuianimation.h:13
MythOpenGLPainter::End
void End() override
Definition: mythpainteropengl.cpp:150
MythImage::IsChanged
bool IsChanged() const
Definition: mythimage.h:51
MythRenderOpenGL::SetViewPort
void SetViewPort(QRect Rect, bool ViewportOnly=false) override
Definition: mythrenderopengl.cpp:584
MythOpenGLPainter::~MythOpenGLPainter
~MythOpenGLPainter() override
Definition: mythpainteropengl.cpp:24
MythPainter::Teardown
virtual void Teardown(void)
Definition: mythpainter.cpp:28
MythPainter::CheckFormatImage
void CheckFormatImage(MythImage *im)
Definition: mythpainter.cpp:556
mythmainwindow.h
MythOpenGLPainter::DrawRoundRect
void DrawRoundRect(QRect Area, int CornerRadius, const QBrush &FillBrush, const QPen &LinePen, int Alpha) override
Definition: mythpainteropengl.cpp:324
MythOpenGLPainter::DrawImage
void DrawImage(QRect Dest, MythImage *Image, QRect Source, int Alpha) override
Definition: mythpainteropengl.cpp:246
MythPainter::Begin
virtual void Begin(QPaintDevice *)
Definition: mythpainter.h:54
MythPainter::DrawRoundRect
virtual void DrawRoundRect(QRect area, int cornerRadius, const QBrush &fillBrush, const QPen &linePen, int alpha)
Definition: mythpainter.cpp:168
MythMainWindow
Definition: mythmainwindow.h:28
MythOpenGLPainter::m_imageToTextureMap
QMap< MythImage *, MythGLTexture * > m_imageToTextureMap
Definition: mythpainteropengl.h:71
MythRenderOpenGL::CreateShaderProgram
QOpenGLShaderProgram * CreateShaderProgram(const QString &Vertex, const QString &Fragment)
Definition: mythrenderopengl.cpp:1416
MythOpenGLPainter::m_textureDeleteList
std::list< MythGLTexture * > m_textureDeleteList
Definition: mythpainteropengl.h:73
MythOpenGLPainter::ClearCache
void ClearCache(void)
Definition: mythpainteropengl.cpp:75
MythPainterGPU
Definition: mythpaintergpu.h:11
OpenGLLocker
Definition: mythrenderopengl.h:263