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