MythTV  master
mythrenderopengl.cpp
Go to the documentation of this file.
1 // Std
2 #include <algorithm>
3 #include <cmath>
4 
5 // Qt
6 #include <QLibrary>
7 #include <QPainter>
8 #include <QWindow>
9 #include <QWidget>
10 #include <QGuiApplication>
11 
12 // MythTV
15 
16 #include "mythmainwindow.h"
17 #include "mythrenderopengl.h"
19 #include "mythuitype.h"
20 #ifdef USING_X11
21 #include "platforms/mythxdisplay.h"
22 #endif
23 
24 #define LOC QString("OpenGL: ")
25 
26 #ifdef Q_OS_ANDROID
27 #include <android/log.h>
28 #include <QWindow>
29 #endif
30 
31 static constexpr GLuint VERTEX_INDEX { 0 };
32 static constexpr GLuint COLOR_INDEX { 1 };
33 static constexpr GLuint TEXTURE_INDEX { 2 };
34 static constexpr GLint VERTEX_SIZE { 2 };
35 static constexpr GLint TEXTURE_SIZE { 2 };
36 
37 static constexpr GLuint kVertexOffset { 0 };
38 static constexpr GLuint kTextureOffset { 8 * sizeof(GLfloat) };
39 
40 static constexpr int MAX_VERTEX_CACHE { 500 };
41 
42 MythGLTexture::MythGLTexture(QOpenGLTexture *Texture)
43  : m_texture(Texture)
44 {
45 }
46 
48  : m_textureId(Texture)
49 {
50 }
51 
53  : m_render(Render)
54 {
55  if (m_render)
57 }
58 
60 {
61  if (m_render)
63 }
64 
66 {
67  // Don't try and create the window
68  if (!HasMythMainWindow())
69  return nullptr;
70 
72  if (!window)
73  return nullptr;
74 
75  auto* result = dynamic_cast<MythRenderOpenGL*>(window->GetRenderDevice());
76  if (result)
77  return result;
78  return nullptr;
79 }
80 
82 {
83  if (!Widget)
84  return nullptr;
85 
86 #ifdef USING_X11
88  {
89  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL is disabled for Remote X Session");
90  return nullptr;
91  }
92 #endif
93 
94  // N.B the core profiles below are designed to target compute shader availability
95  bool opengles = !qEnvironmentVariableIsEmpty("MYTHTV_OPENGL_ES");
96  bool core = !qEnvironmentVariableIsEmpty("MYTHTV_OPENGL_CORE");
97  QSurfaceFormat format = QSurfaceFormat::defaultFormat();
98  if (core)
99  {
100  format.setProfile(QSurfaceFormat::CoreProfile);
101  format.setMajorVersion(4);
102  format.setMinorVersion(3);
103  }
104 
105  if (opengles)
106  {
107  if (core)
108  {
109  format.setProfile(QSurfaceFormat::CoreProfile);
110  format.setMajorVersion(3);
111  format.setMinorVersion(1);
112  }
113  format.setRenderableType(QSurfaceFormat::OpenGLES);
114  }
115 
116  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
117  format.setOption(QSurfaceFormat::DebugContext);
118 
119  return new MythRenderOpenGL(format, Widget);
120 }
121 
122 MythRenderOpenGL::MythRenderOpenGL(const QSurfaceFormat& Format, QWidget *Widget)
123  : MythEGL(this),
125  m_fullRange(gCoreContext->GetBoolSetting("GUIRGBLevels", true))
126 {
127  m_projection.fill(0);
128  m_parameters.fill(0);
129  m_transforms.push(QMatrix4x4());
130  setFormat(Format);
131  connect(this, &QOpenGLContext::aboutToBeDestroyed, this, &MythRenderOpenGL::contextToBeDestroyed);
132  SetWidget(Widget);
133 }
134 
136 {
137  LOG(VB_GENERAL, LOG_INFO, LOC + "MythRenderOpenGL closing");
138  if (!isValid())
139  return;
140  disconnect(this, &QOpenGLContext::aboutToBeDestroyed, this, &MythRenderOpenGL::contextToBeDestroyed);
141  if (m_ready)
143 }
144 
145 void MythRenderOpenGL::MessageLogged(const QOpenGLDebugMessage &Message)
146 {
147  // filter unwanted messages
148  if ((m_openGLDebuggerFilter & Message.type()) != 0U)
149  return;
150 
151  QString source("Unknown");
152  QString type("Unknown");
153 
154  switch (Message.source())
155  {
156  case QOpenGLDebugMessage::ApplicationSource: return; // filter out our own messages
157  case QOpenGLDebugMessage::APISource: source = "API"; break;
158  case QOpenGLDebugMessage::WindowSystemSource: source = "WinSys"; break;
159  case QOpenGLDebugMessage::ShaderCompilerSource: source = "ShaderComp"; break;
160  case QOpenGLDebugMessage::ThirdPartySource: source = "3rdParty"; break;
161  case QOpenGLDebugMessage::OtherSource: source = "Other"; break;
162  default: break;
163  }
164 
165  // N.B. each break is on a separate line to allow setting individual break points
166  // when using synchronous logging
167  switch (Message.type())
168  {
169  case QOpenGLDebugMessage::ErrorType:
170  type = "Error"; break;
171  case QOpenGLDebugMessage::DeprecatedBehaviorType:
172  type = "Deprecated"; break;
173  case QOpenGLDebugMessage::UndefinedBehaviorType:
174  type = "Undef behaviour"; break;
175  case QOpenGLDebugMessage::PortabilityType:
176  type = "Portability"; break;
177  case QOpenGLDebugMessage::PerformanceType:
178  type = "Performance"; break;
179  case QOpenGLDebugMessage::OtherType:
180  type = "Other"; break;
181  case QOpenGLDebugMessage::MarkerType:
182  type = "Marker"; break;
183  case QOpenGLDebugMessage::GroupPushType:
184  type = "GroupPush"; break;
185  case QOpenGLDebugMessage::GroupPopType:
186  type = "GroupPop"; break;
187  default: break;
188  }
189  LOG(VB_GPU, LOG_INFO, LOC + QString("Src: %1 Type: %2 Msg: %3")
190  .arg(source, type, Message.message()));
191 }
192 
193 void MythRenderOpenGL:: logDebugMarker(const QString &Message)
194 {
195  if (m_openglDebugger)
196  {
197  QOpenGLDebugMessage message = QOpenGLDebugMessage::createApplicationMessage(
198  Message, 0, QOpenGLDebugMessage::NotificationSeverity, QOpenGLDebugMessage::MarkerType);
199  m_openglDebugger->logMessage(message);
200  }
201 }
202 
203 // Can't be static because its connected to a signal and passed "this".
204 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
206 {
207  LOG(VB_GENERAL, LOG_WARNING, LOC + "Context about to be destroyed");
208 }
209 
211 {
212  if (!isValid())
213  {
214  LOG(VB_GENERAL, LOG_ERR, LOC + "MythRenderOpenGL is not a valid OpenGL rendering context");
215  return false;
216  }
217 
218  OpenGLLocker locker(this);
219  initializeOpenGLFunctions();
220  m_ready = true;
221  m_features = openGLFeatures();
222 
223  // don't enable this by default - it can generate a lot of detail
224  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
225  {
226  m_openglDebugger = new QOpenGLDebugLogger();
227  if (m_openglDebugger->initialize())
228  {
229  connect(m_openglDebugger, &QOpenGLDebugLogger::messageLogged, this, &MythRenderOpenGL::MessageLogged);
230  QOpenGLDebugLogger::LoggingMode mode = QOpenGLDebugLogger::AsynchronousLogging;
231 
232  // this will impact performance but can be very useful
233  if (!qEnvironmentVariableIsEmpty("MYTHTV_OPENGL_SYNCHRONOUS"))
234  mode = QOpenGLDebugLogger::SynchronousLogging;
235 
236  m_openglDebugger->startLogging(mode);
237  if (mode == QOpenGLDebugLogger::AsynchronousLogging)
238  LOG(VB_GENERAL, LOG_INFO, LOC + "GPU debug logging started (async)");
239  else
240  LOG(VB_GENERAL, LOG_INFO, LOC + "Started synchronous GPU debug logging (will hurt performance)");
241 
242  // filter messages. Some drivers can be extremely verbose for certain issues.
243  QStringList debug;
244  QString filter = qgetenv("MYTHTV_OPENGL_LOGFILTER");
245  if (filter.contains("other", Qt::CaseInsensitive))
246  {
247  m_openGLDebuggerFilter |= QOpenGLDebugMessage::OtherType;
248  debug << "Other";
249  }
250  if (filter.contains("error", Qt::CaseInsensitive))
251  {
252  m_openGLDebuggerFilter |= QOpenGLDebugMessage::ErrorType;
253  debug << "Error";
254  }
255  if (filter.contains("deprecated", Qt::CaseInsensitive))
256  {
257  m_openGLDebuggerFilter |= QOpenGLDebugMessage::DeprecatedBehaviorType;
258  debug << "Deprecated";
259  }
260  if (filter.contains("undefined", Qt::CaseInsensitive))
261  {
262  m_openGLDebuggerFilter |= QOpenGLDebugMessage::UndefinedBehaviorType;
263  debug << "Undefined";
264  }
265  if (filter.contains("portability", Qt::CaseInsensitive))
266  {
267  m_openGLDebuggerFilter |= QOpenGLDebugMessage::PortabilityType;
268  debug << "Portability";
269  }
270  if (filter.contains("performance", Qt::CaseInsensitive))
271  {
272  m_openGLDebuggerFilter |= QOpenGLDebugMessage::PerformanceType;
273  debug << "Performance";
274  }
275  if (filter.contains("grouppush", Qt::CaseInsensitive))
276  {
277  m_openGLDebuggerFilter |= QOpenGLDebugMessage::GroupPushType;
278  debug << "GroupPush";
279  }
280  if (filter.contains("grouppop", Qt::CaseInsensitive))
281  {
282  m_openGLDebuggerFilter |= QOpenGLDebugMessage::GroupPopType;
283  debug << "GroupPop";
284  }
285 
286  if (!debug.isEmpty())
287  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Filtering out GPU messages for: %1")
288  .arg(debug.join(", ")));
289  }
290  else
291  {
292  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to initialise OpenGL logging");
293  delete m_openglDebugger;
294  m_openglDebugger = nullptr;
295  }
296  }
297 
298  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
299  logDebugMarker("RENDER_INIT_START");
300 
301  Init2DState();
302 
303  // basic features
304  GLint maxtexsz = 0;
305  GLint maxunits = 0;
306  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsz);
307  glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxunits);
308  m_maxTextureUnits = maxunits;
309  m_maxTextureSize = (maxtexsz) ? maxtexsz : 512;
310  QSurfaceFormat fmt = format();
311 
312  // Pixel buffer objects
313  bool buffer_procs = reinterpret_cast<MYTH_GLMAPBUFFERPROC>(GetProcAddress("glMapBuffer")) &&
314  reinterpret_cast<MYTH_GLUNMAPBUFFERPROC>(GetProcAddress("glUnmapBuffer"));
315 
316  // Buffers are available by default (GL and GLES).
317  // Buffer mapping is available by extension
318  if ((isOpenGLES() && hasExtension("GL_OES_mapbuffer") && buffer_procs) ||
319  (hasExtension("GL_ARB_vertex_buffer_object") && buffer_procs))
321 
322  // Rectangular textures
323  if (!isOpenGLES() && (hasExtension("GL_NV_texture_rectangle") ||
324  hasExtension("GL_ARB_texture_rectangle") ||
325  hasExtension("GL_EXT_texture_rectangle")))
327 
328  // GL_RED etc texure formats. Not available on GLES2.0 or GL < 2
329  if ((isOpenGLES() && format().majorVersion() < 3) ||
330  (!isOpenGLES() && format().majorVersion() < 2))
332 
333  // GL_UNPACK_ROW_LENGTH - for uploading video textures
334  // Note: Should also be available on GL1.4 per specification
335  if (!isOpenGLES() || (isOpenGLES() && ((fmt.majorVersion() >= 3) || hasExtension("GL_EXT_unpack_subimage"))))
337 
338  // check for core profile N.B. not OpenGL ES
339  if (fmt.profile() == QSurfaceFormat::OpenGLContextProfile::CoreProfile)
340  {
341  // if we have a core profile then we need a VAO bound - this is just a
342  // workaround for the time being
343  extraFunctions()->glGenVertexArrays(1, &m_vao);
344  extraFunctions()->glBindVertexArray(m_vao);
345  }
346 
347  // For (embedded) GPUs that use tile based rendering, it is faster to use
348  // glClear e.g. on the Pi3 it improves video frame rate significantly. Using
349  // glClear tells the GPU it doesn't have to retrieve the old framebuffer and will
350  // also clear existing draw calls.
351  // For now this just includes Broadcom VideoCoreIV.
352  // Other Tile Based Deferred Rendering GPUS - PowerVR5/6/7, Apple (PowerVR as well?)
353  // Other Tile Based Immediate Mode Rendering GPUS - ARM Mali, Qualcomm Adreno
354  static const std::array<const QByteArray,3> kTiled { "videocore", "vc4", "v3d" };
355  auto renderer = QByteArray(reinterpret_cast<const char*>(glGetString(GL_RENDERER))).toLower();
356  for (const auto & name : kTiled)
357  {
358  if (renderer.contains(name))
359  {
361  break;
362  }
363  }
364 
365  // Check for memory extensions
366  if (hasExtension("GL_NVX_gpu_memory_info"))
368 
369  // Check 16 bit FBOs
370  Check16BitFBO();
371 
372  // Check for compute and geometry shaders
373  if (QOpenGLShader::hasOpenGLShaders(QOpenGLShader::Compute))
375  if (QOpenGLShader::hasOpenGLShaders(QOpenGLShader::Geometry))
377 
378  DebugFeatures();
379 
381  if (!CreateDefaultShaders())
382  {
383  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create default shaders");
384  return false;
385  }
386 
387  LOG(VB_GENERAL, LOG_INFO, LOC + "Initialised MythRenderOpenGL");
388  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using %1 range output").arg(m_fullRange ? "full" : "limited"));
389  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
390  logDebugMarker("RENDER_INIT_END");
391  return true;
392 }
393 
394 static constexpr QLatin1String GLYesNo (bool v)
395 {
396  return v ? QLatin1String("Yes") : QLatin1String("No");
397 }
398 
400 {
401  QSurfaceFormat fmt = format();
402  QString qtglversion = QString("OpenGL%1 %2.%3")
403  .arg(fmt.renderableType() == QSurfaceFormat::OpenGLES ? "ES" : "")
404  .arg(fmt.majorVersion()).arg(fmt.minorVersion());
405  QString qtglsurface = QString("RGBA: %1:%2:%3:%4 Depth: %5 Stencil: %6")
406  .arg(fmt.redBufferSize()).arg(fmt.greenBufferSize())
407  .arg(fmt.blueBufferSize()).arg(fmt.alphaBufferSize())
408  .arg(fmt.depthBufferSize()).arg(fmt.stencilBufferSize());
409  QStringList shaders {"None"};
410  if (m_features & Shaders)
411  {
412  shaders = QStringList { "Vertex", "Fragment" };
414  shaders << "Geometry";
416  shaders << "Compute";
417  }
418  const QString module = QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL ? "OpenGL (not ES)" : "OpenGL ES";
419  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL vendor : %1").arg(reinterpret_cast<const char*>(glGetString(GL_VENDOR))));
420  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL renderer : %1").arg(reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
421  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL version : %1").arg(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
422  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt platform : %1").arg(QGuiApplication::platformName()));
423 #ifdef USING_EGL
424  bool eglfuncs = IsEGL();
425  LOG(VB_GENERAL, LOG_INFO, LOC + QString("EGL display : %1").arg(GLYesNo(GetEGLDisplay() != nullptr)));
426  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("EGL images : %1").arg(GLYesNo(eglfuncs)));
427 #endif
428  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt OpenGL module : %1").arg(module));
429  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt OpenGL format : %1").arg(qtglversion));
430  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt OpenGL surface : %1").arg(qtglsurface));
431  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture size : %1").arg(m_maxTextureSize));
432  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Shaders : %1").arg(shaders.join(",")));
433  LOG(VB_GENERAL, LOG_INFO, LOC + QString("16bit framebuffers : %1").arg(GLYesNo(m_extraFeatures & kGL16BitFBO)));
434  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Unpack Subimage : %1").arg(GLYesNo(m_extraFeatures & kGLExtSubimage)));
435  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Buffer mapping : %1").arg(GLYesNo(m_extraFeatures & kGLBufferMap)));
436  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Rectangular textures : %1").arg(GLYesNo(m_extraFeatures & kGLExtRects)));
437  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("NPOT textures : %1").arg(GLYesNo(m_features & NPOTTextures)));
438  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Max texture units : %1").arg(m_maxTextureUnits));
439  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("GL_RED/GL_R8 : %1").arg(GLYesNo(!(m_extraFeatures & kGLLegacyTextures))));
440  // warnings
441  if (m_maxTextureUnits < 3)
442  LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning: Insufficient texture units for some features.");
443 }
444 
446 {
447  return m_maxTextureSize;
448 }
449 
451 {
452  return m_maxTextureUnits;
453 }
454 
456 {
457  return m_extraFeaturesUsed;
458 }
459 
460 QOpenGLFunctions::OpenGLFeatures MythRenderOpenGL::GetFeatures(void) const
461 {
462  return m_features;
463 }
464 
466 {
467  if (!IsReady())
468  return false;
469 
470  bool recommended = true;
471  OpenGLLocker locker(this);
472  QString renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
473 
474  if (!(openGLFeatures() & Shaders))
475  {
476  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL has no shader support");
477  recommended = false;
478  }
479  else if (!(openGLFeatures() & Framebuffers))
480  {
481  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL has no framebuffer support");
482  recommended = false;
483  }
484  else if (renderer.contains("Software Rasterizer", Qt::CaseInsensitive))
485  {
486  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL is using software rasterizer.");
487  recommended = false;
488  }
489  else if (renderer.contains("softpipe", Qt::CaseInsensitive))
490  {
491  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL seems to be using software "
492  "fallback. Please check your OpenGL driver installation, "
493  "configuration, and device permissions.");
494  recommended = false;
495  }
496 
497  if (!recommended)
498  {
499  LOG(VB_GENERAL, LOG_INFO, LOC +
500  "OpenGL not recommended with this system's hardware/drivers.");
501  }
502 
503  return recommended;
504 }
505 
507 {
508  return isValid() && m_ready;
509 }
510 
512 {
513  QOpenGLContext::swapBuffers(m_window);
514  m_swapCount++;
515 }
516 
518 {
519  auto result = m_swapCount;
520  m_swapCount = 0;
521  return result;
522 }
523 
524 void MythRenderOpenGL::SetWidget(QWidget *Widget)
525 {
526  if (!Widget)
527  {
528  LOG(VB_GENERAL, LOG_CRIT, LOC + "No widget!");
529  return;
530  }
531 
532  // We must have a window/surface.
533  m_window = Widget->windowHandle();
534  QWidget* native = Widget->nativeParentWidget();
535  if (!m_window && native)
536  m_window = native->windowHandle();
537 
538  if (!m_window)
539  {
540  LOG(VB_GENERAL, LOG_CRIT, LOC + "No window surface!");
541  return;
542  }
543 
544 #ifdef Q_OS_ANDROID
545  // Ensure surface type is always OpenGL
546  m_window->setSurfaceType(QWindow::OpenGLSurface);
547  if (native && native->windowHandle())
548  native->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
549 #endif
550 
551 #ifdef USING_QTWEBENGINE
552  auto * globalcontext = QOpenGLContext::globalShareContext();
553  if (globalcontext)
554  {
555  LOG(VB_GENERAL, LOG_INFO, LOC + "Using global shared OpenGL context");
556  setShareContext(globalcontext);
557  }
558 #endif
559 
560  if (!create())
561  LOG(VB_GENERAL, LOG_CRIT, LOC + "Failed to create OpenGLContext!");
562  else
563  Widget->setAttribute(Qt::WA_PaintOnScreen);
564 }
565 
567 {
568  m_lock.lock();
569  if (!m_lockLevel++)
570  if (!QOpenGLContext::makeCurrent(m_window))
571  LOG(VB_GENERAL, LOG_ERR, LOC + "makeCurrent failed");
572 }
573 
575 {
576  // TODO add back QOpenGLContext::doneCurrent call
577  // once calls are better pipelined
578  m_lockLevel--;
579  if (m_lockLevel < 0)
580  LOG(VB_GENERAL, LOG_ERR, LOC + "Mis-matched calls to makeCurrent()");
581  m_lock.unlock();
582 }
583 
584 void MythRenderOpenGL::SetViewPort(QRect Rect, bool ViewportOnly)
585 {
586  if (Rect == m_viewport)
587  return;
588  makeCurrent();
589  m_viewport = Rect;
590  glViewport(m_viewport.left(), m_viewport.top(),
591  m_viewport.width(), m_viewport.height());
592  if (!ViewportOnly)
593  SetMatrixView();
594  doneCurrent();
595 }
596 
598 {
599  if (!m_flushEnabled)
600  return;
601 
602  makeCurrent();
603  glFlush();
604  doneCurrent();
605 }
606 
607 void MythRenderOpenGL::SetBlend(bool Enable)
608 {
609  makeCurrent();
610  if (Enable && !m_blend)
611  glEnable(GL_BLEND);
612  else if (!Enable && m_blend)
613  glDisable(GL_BLEND);
614  m_blend = Enable;
615  doneCurrent();
616 }
617 
618 void MythRenderOpenGL::SetBackground(uint8_t Red, uint8_t Green, uint8_t Blue, uint8_t Alpha)
619 {
620  int32_t tmp = (Red << 24) + (Green << 16) + (Blue << 8) + Alpha;
621  if (tmp == m_background)
622  return;
623 
624  m_background = tmp;
625  makeCurrent();
626  glClearColor(Red / 255.0F, Green / 255.0F, Blue / 255.0F, Alpha / 255.0F);
627  doneCurrent();
628 }
629 
631 {
632  if (!Image)
633  return nullptr;
634 
635  OpenGLLocker locker(this);
636  auto *texture = new QOpenGLTexture(*Image, QOpenGLTexture::DontGenerateMipMaps);
637  if (!texture->textureId())
638  {
639  LOG(VB_GENERAL, LOG_INFO, LOC + "Failed to create texure");
640  delete texture;
641  return nullptr;
642  }
643  texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
644  texture->setWrapMode(QOpenGLTexture::ClampToEdge);
645  auto *result = new MythGLTexture(texture);
646  result->m_texture = texture;
647  result->m_vbo = CreateVBO(kVertexSize);
648  result->m_totalSize = GetTextureSize(Image->size(), result->m_target != QOpenGLTexture::TargetRectangle);
649  // N.B. Format and type per qopengltexure.cpp
650  result->m_pixelFormat = QOpenGLTexture::RGBA;
651  result->m_pixelType = QOpenGLTexture::UInt8;
652  result->m_bufferSize = GetBufferSize(result->m_totalSize, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
653  result->m_size = Image->size();
654  result->m_crop = true;
655  return result;
656 }
657 
658 QSize MythRenderOpenGL::GetTextureSize(const QSize Size, bool Normalised)
659 {
660  if (((m_features & NPOTTextures) != 0U) || !Normalised)
661  return Size;
662 
663  int w = 64;
664  int h = 64;
665  while (w < Size.width())
666  w *= 2;
667  while (h < Size.height())
668  h *= 2;
669  return {w, h};
670 }
671 
673 {
674  if (Texture)
675  return Texture->m_bufferSize;
676  return 0;
677 }
678 
679 void MythRenderOpenGL::SetTextureFilters(MythGLTexture *Texture, QOpenGLTexture::Filter Filter, QOpenGLTexture::WrapMode Wrap)
680 {
681  if (!Texture || !(Texture->m_texture || Texture->m_textureId))
682  return;
683 
684  makeCurrent();
685  if (Texture->m_texture)
686  {
687  Texture->m_texture->bind();
688  Texture->m_texture->setWrapMode(Wrap);
689  Texture->m_texture->setMinMagFilters(Filter, Filter);
690  }
691  else
692  {
693  glBindTexture(Texture->m_target, Texture->m_textureId);
694  glTexParameteri(Texture->m_target, GL_TEXTURE_MIN_FILTER, Filter);
695  glTexParameteri(Texture->m_target, GL_TEXTURE_MAG_FILTER, Filter);
696  glTexParameteri(Texture->m_target, GL_TEXTURE_WRAP_S, Wrap);
697  glTexParameteri(Texture->m_target, GL_TEXTURE_WRAP_T, Wrap);
698  }
699  doneCurrent();
700 }
701 
702 void MythRenderOpenGL::ActiveTexture(GLuint ActiveTex)
703 {
704  if (!(m_features & Multitexture))
705  return;
706 
707  makeCurrent();
708  if (m_activeTexture != ActiveTex)
709  {
710  glActiveTexture(ActiveTex);
711  m_activeTexture = ActiveTex;
712  }
713  doneCurrent();
714 }
715 
717 {
718  if (!Texture)
719  return;
720 
721  makeCurrent();
722  // N.B. Don't delete m_textureId - it is owned externally
723  delete Texture->m_texture;
724  delete [] Texture->m_data;
725  delete Texture->m_vbo;
726  delete Texture;
727  Flush();
728  doneCurrent();
729 }
730 
731 QOpenGLFramebufferObject* MythRenderOpenGL::CreateFramebuffer(QSize &Size, bool SixteenBit)
732 {
733  if (!(m_features & Framebuffers))
734  return nullptr;
735 
736  OpenGLLocker locker(this);
737  QOpenGLFramebufferObject *framebuffer = nullptr;
738  if (SixteenBit)
739  {
740  framebuffer = new QOpenGLFramebufferObject(Size, QOpenGLFramebufferObject::NoAttachment,
741  GL_TEXTURE_2D, QOpenGLTexture::RGBA16_UNorm);
742  }
743  else
744  {
745  framebuffer = new QOpenGLFramebufferObject(Size);
746  }
747  if (framebuffer->isValid())
748  {
749  if (framebuffer->isBound())
750  {
751  m_activeFramebuffer = framebuffer->handle();
752  BindFramebuffer(nullptr);
753  }
754  Flush();
755  return framebuffer;
756  }
757  LOG(VB_GENERAL, LOG_ERR, "Failed to create framebuffer object");
758  delete framebuffer;
759  return nullptr;
760 }
761 
763 MythGLTexture* MythRenderOpenGL::CreateFramebufferTexture(QOpenGLFramebufferObject *Framebuffer)
764 {
765  if (!Framebuffer)
766  return nullptr;
767 
768  auto *texture = new MythGLTexture(Framebuffer->texture());
769  texture->m_size = texture->m_totalSize = Framebuffer->size();
770  texture->m_vbo = CreateVBO(kVertexSize);
771  texture->m_flip = false;
772  return texture;
773 }
774 
775 void MythRenderOpenGL::DeleteFramebuffer(QOpenGLFramebufferObject *Framebuffer)
776 {
777  if (Framebuffer)
778  {
779  makeCurrent();
780  delete Framebuffer;
781  doneCurrent();
782  }
783 }
784 
785 void MythRenderOpenGL::BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
786 {
787  if ((Framebuffer && Framebuffer->handle() == m_activeFramebuffer) ||
788  (!Framebuffer && defaultFramebufferObject() == m_activeFramebuffer))
789  return;
790 
791  makeCurrent();
792  if (Framebuffer == nullptr)
793  {
794  QOpenGLFramebufferObject::bindDefault();
795  m_activeFramebuffer = defaultFramebufferObject();
796  }
797  else
798  {
799  Framebuffer->bind();
800  m_activeFramebuffer = Framebuffer->handle();
801  }
802  doneCurrent();
803 }
804 
806 {
807  makeCurrent();
808  glClear(GL_COLOR_BUFFER_BIT);
809  doneCurrent();
810 }
811 
812 void MythRenderOpenGL::DrawProcedural(QRect Area, int Alpha, QOpenGLFramebufferObject* Target,
813  QOpenGLShaderProgram *Program, float TimeVal)
814 {
815  if (!Program)
816  return;
817 
818  makeCurrent();
819  BindFramebuffer(Target);
820  glEnableVertexAttribArray(VERTEX_INDEX);
821  GetCachedVBO(GL_TRIANGLE_STRIP, Area);
822  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
823  SetShaderProjection(Program);
824  Program->setUniformValue("u_time", TimeVal);
825  Program->setUniformValue("u_alpha", static_cast<float>(Alpha / 255.0F));
826  Program->setUniformValue("u_res", QVector2D(m_window->width(), m_window->height()));
827  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
828  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
829  glDisableVertexAttribArray(VERTEX_INDEX);
830  doneCurrent();
831 }
832 
833 void MythRenderOpenGL::DrawBitmap(MythGLTexture *Texture, QOpenGLFramebufferObject *Target,
834  const QRect Source, const QRect Destination,
835  QOpenGLShaderProgram *Program, int Alpha, qreal Scale)
836 {
837  makeCurrent();
838 
839  if (!Texture || !((Texture->m_texture || Texture->m_textureId) && Texture->m_vbo))
840  return;
841 
842  if (Program == nullptr)
844 
845  BindFramebuffer(Target);
846  SetShaderProjection(Program);
847 
848  GLenum textarget = Texture->m_target;
849  Program->setUniformValue("s_texture0", 0);
851  if (Texture->m_texture)
852  Texture->m_texture->bind();
853  else
854  glBindTexture(textarget, Texture->m_textureId);
855 
856  QOpenGLBuffer* buffer = Texture->m_vbo;
857  buffer->bind();
858  if (UpdateTextureVertices(Texture, Source, Destination, 0, Scale))
859  {
861  {
862  void* target = buffer->map(QOpenGLBuffer::WriteOnly);
863  if (target)
864  {
865  std::copy(Texture->m_vertexData.cbegin(),
866  Texture->m_vertexData.cend(),
867  static_cast<GLfloat*>(target));
868  }
869  buffer->unmap();
870  }
871  else
872  {
873  buffer->write(0, Texture->m_vertexData.data(), kVertexSize);
874  }
875  }
876 
877  glEnableVertexAttribArray(VERTEX_INDEX);
878  glEnableVertexAttribArray(TEXTURE_INDEX);
879  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
880  glVertexAttrib4f(COLOR_INDEX, 1.0F, 1.0F, 1.0F, Alpha / 255.0F);
881  glVertexAttribPointerI(TEXTURE_INDEX, TEXTURE_SIZE, GL_FLOAT, GL_FALSE, TEXTURE_SIZE * sizeof(GLfloat), kTextureOffset);
882  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
883  glDisableVertexAttribArray(TEXTURE_INDEX);
884  glDisableVertexAttribArray(VERTEX_INDEX);
885  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
886  doneCurrent();
887 }
888 
889 void MythRenderOpenGL::DrawBitmap(std::vector<MythGLTexture *> &Textures,
890  QOpenGLFramebufferObject *Target,
891  const QRect Source, const QRect Destination,
892  QOpenGLShaderProgram *Program,
893  int Rotation)
894 {
895  if (Textures.empty())
896  return;
897 
898  makeCurrent();
899  BindFramebuffer(Target);
900 
901  if (Program == nullptr)
903 
904  MythGLTexture* first = Textures[0];
905  if (!first || !((first->m_texture || first->m_textureId) && first->m_vbo))
906  return;
907 
908  SetShaderProjection(Program);
909 
910  GLenum textarget = first->m_target;
911  for (uint i = 0; i < Textures.size(); i++)
912  {
913  QString uniform = QString("s_texture%1").arg(i);
914  Program->setUniformValue(qPrintable(uniform), i);
916  if (Textures[i]->m_texture)
917  Textures[i]->m_texture->bind();
918  else
919  glBindTexture(textarget, Textures[i]->m_textureId);
920  }
921 
922  QOpenGLBuffer* buffer = first->m_vbo;
923  buffer->bind();
924  if (UpdateTextureVertices(first, Source, Destination, Rotation))
925  {
927  {
928  void* target = buffer->map(QOpenGLBuffer::WriteOnly);
929  if (target)
930  {
931  std::copy(first->m_vertexData.cbegin(),
932  first->m_vertexData.cend(),
933  static_cast<GLfloat*>(target));
934  }
935  buffer->unmap();
936  }
937  else
938  {
939  buffer->write(0, first->m_vertexData.data(), kVertexSize);
940  }
941  }
942 
943  glEnableVertexAttribArray(VERTEX_INDEX);
944  glEnableVertexAttribArray(TEXTURE_INDEX);
945  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
946  glVertexAttrib4f(COLOR_INDEX, 1.0, 1.0, 1.0, 1.0);
947  glVertexAttribPointerI(TEXTURE_INDEX, TEXTURE_SIZE, GL_FLOAT, GL_FALSE, TEXTURE_SIZE * sizeof(GLfloat), kTextureOffset);
948  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
949  glDisableVertexAttribArray(TEXTURE_INDEX);
950  glDisableVertexAttribArray(VERTEX_INDEX);
951  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
952  doneCurrent();
953 }
954 
955 static const float kLimitedRangeOffset = (16.0F / 255.0F);
956 static const float kLimitedRangeScale = (219.0F / 255.0F);
957 
959 void MythRenderOpenGL::ClearRect(QOpenGLFramebufferObject *Target, const QRect Area, int Color, int Alpha)
960 {
961  makeCurrent();
962  BindFramebuffer(Target);
963  glEnableVertexAttribArray(VERTEX_INDEX);
964 
965  // Set the fill color
966  float color = m_fullRange ? Color / 255.0F : (Color * kLimitedRangeScale) + kLimitedRangeOffset;
967  glVertexAttrib4f(COLOR_INDEX, color, color, color, Alpha / 255.0F);
969 
970  GetCachedVBO(GL_TRIANGLE_STRIP, Area);
971  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
972  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
973 
974  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
975  glDisableVertexAttribArray(VERTEX_INDEX);
976  doneCurrent();
977 }
978 
979 void MythRenderOpenGL::DrawRect(QOpenGLFramebufferObject *Target,
980  const QRect Area, const QBrush &FillBrush,
981  const QPen &LinePen, int Alpha)
982 {
983  DrawRoundRect(Target, Area, 1, FillBrush, LinePen, Alpha);
984 }
985 
986 
987 void MythRenderOpenGL::DrawRoundRect(QOpenGLFramebufferObject *Target,
988  const QRect Area, int CornerRadius,
989  const QBrush &FillBrush,
990  const QPen &LinePen, int Alpha)
991 {
992  bool fill = FillBrush.style() != Qt::NoBrush;
993  bool edge = LinePen.style() != Qt::NoPen;
994  if (!(fill || edge))
995  return;
996 
997  auto SetColor = [&](const QColor& Color)
998  {
999  if (m_fullRange)
1000  {
1001  glVertexAttrib4f(COLOR_INDEX, Color.red() / 255.0F, Color.green() / 255.0F,
1002  Color.blue() / 255.0F, (Color.alpha() / 255.0F) * (Alpha / 255.0F));
1003  return;
1004  }
1005  glVertexAttrib4f(COLOR_INDEX, (Color.red() * kLimitedRangeScale) + kLimitedRangeOffset,
1008  (Color.alpha() / 255.0F) * (Alpha / 255.0F));
1009  };
1010 
1011  float halfwidth = Area.width() / 2.0F;
1012  float halfheight = Area.height() / 2.0F;
1013  float radius = CornerRadius;
1014  if (radius < 1.0F) radius = 1.0F;
1015  if (radius > halfwidth) radius = halfwidth;
1016  if (radius > halfheight) radius = halfheight;
1017 
1018  // Set shader parameters
1019  // Centre of the rectangle
1020  m_parameters(0,0) = Area.left() + halfwidth;
1021  m_parameters(1,0) = Area.top() + halfheight;
1022  m_parameters(2,0) = radius;
1023  // Rectangle 'size' - distances from the centre to the edge
1024  m_parameters(0,1) = halfwidth;
1025  m_parameters(1,1) = halfheight;
1026 
1027  makeCurrent();
1028  BindFramebuffer(Target);
1029  glEnableVertexAttribArray(VERTEX_INDEX);
1030  GetCachedVBO(GL_TRIANGLE_STRIP, Area);
1031  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1032 
1033  if (fill)
1034  {
1035  SetColor(FillBrush.color());
1038  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1039  }
1040 
1041  if (edge)
1042  {
1043  float innerradius = radius - LinePen.width();
1044  if (innerradius < 1.0F) innerradius = 1.0F;
1045  m_parameters(3,0) = innerradius;
1046  // Adjust the size for the inner radius (edge)
1047  m_parameters(2,1) = halfwidth - LinePen.width();
1048  m_parameters(3,1) = halfheight - LinePen.width();
1049  SetColor(LinePen.color());
1052  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1053  }
1054 
1055  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1056  glDisableVertexAttribArray(VERTEX_INDEX);
1057  doneCurrent();
1058 }
1059 
1060 inline void MythRenderOpenGL::glVertexAttribPointerI(GLuint Index, GLint Size, GLenum Type, GLboolean Normalize,
1061  GLsizei Stride, const GLuint Value)
1062 {
1063 #pragma GCC diagnostic push
1064 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
1065  glVertexAttribPointer(Index, Size, Type, Normalize, Stride, reinterpret_cast<const char *>(Value));
1066 #pragma GCC diagnostic pop
1067 }
1068 
1070 {
1071  SetBlend(true);
1072  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1073  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1074  glDisable(GL_DEPTH_TEST);
1075  glDepthMask(GL_FALSE);
1076  glDisable(GL_CULL_FACE);
1077  glClearColor(0.0F, 0.0F, 0.0F, 0.0F);
1078  glClear(GL_COLOR_BUFFER_BIT);
1079  QOpenGLFramebufferObject::bindDefault();
1080  m_activeFramebuffer = defaultFramebufferObject();
1081  Flush();
1082 }
1083 
1084 QFunctionPointer MythRenderOpenGL::GetProcAddress(const QString &Proc) const
1085 {
1086  static const std::array<const QString,4> kExts { "", "ARB", "EXT", "OES" };
1087  QFunctionPointer result = nullptr;
1088  for (const auto & ext : kExts)
1089  {
1090  result = getProcAddress((Proc + ext).toLocal8Bit().constData());
1091  if (result)
1092  break;
1093  }
1094  if (result == nullptr)
1095  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Extension not found: %1").arg(Proc));
1096  return result;
1097 }
1098 
1099 QOpenGLBuffer* MythRenderOpenGL::CreateVBO(int Size, bool Release /*=true*/)
1100 {
1101  OpenGLLocker locker(this);
1102  auto* buffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
1103  if (buffer->create())
1104  {
1105  buffer->setUsagePattern(QOpenGLBuffer::StreamDraw);
1106  buffer->bind();
1107  buffer->allocate(Size);
1108  if (Release)
1109  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1110  return buffer;
1111  }
1112  delete buffer;
1113  return nullptr;
1114 }
1115 
1117 {
1118  OpenGLLocker locker(this);
1119  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
1120  logDebugMarker("RENDER_RELEASE_START");
1122  ExpireVertices();
1123  ExpireVBOS();
1124  if (m_vao)
1125  {
1126  extraFunctions()->glDeleteVertexArrays(1, &m_vao);
1127  m_vao = 0;
1128  }
1129 
1130  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
1131  logDebugMarker("RENDER_RELEASE_END");
1132  delete m_openglDebugger;
1133  m_openglDebugger = nullptr;
1134  Flush();
1135 
1136  if (!m_cachedVertices.empty())
1137  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired vertices").arg(m_cachedVertices.size()));
1138 
1139  if (!m_cachedVBOS.empty())
1140  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired VBOs").arg(m_cachedVertices.size()));
1141 }
1142 
1144 {
1145  QStringList result;
1146  result.append(tr("QPA platform") + "\t: " + QGuiApplication::platformName());
1147  result.append(tr("OpenGL vendor") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
1148  result.append(tr("OpenGL renderer") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
1149  result.append(tr("OpenGL version") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1150  QSurfaceFormat fmt = format();
1151  result.append(tr("Color depth (RGBA)") + "\t: " + QString("%1:%2:%3:%4")
1152  .arg(fmt.redBufferSize()).arg(fmt.greenBufferSize())
1153  .arg(fmt.blueBufferSize()).arg(fmt.alphaBufferSize()));
1154  return result;
1155 }
1156 
1158  const QRect Destination, int Rotation, qreal Scale)
1159 {
1160  if (!Texture || Texture->m_size.isEmpty())
1161  return false;
1162 
1163  if ((Texture->m_source == Source) && (Texture->m_destination == Destination) &&
1164  (Texture->m_rotation == Rotation))
1165  return false;
1166 
1167  Texture->m_source = Source;
1168  Texture->m_destination = Destination;
1169  Texture->m_rotation = Rotation;
1170 
1171  GLfloat *data = Texture->m_vertexData.data();
1172  QSize size = Texture->m_size;
1173 
1174  int width = Texture->m_crop ? std::min(Source.width(), size.width()) : Source.width();
1175  int height = Texture->m_crop ? std::min(Source.height(), size.height()) : Source.height();
1176 
1177  if (Texture->m_target != QOpenGLTexture::TargetRectangle)
1178  {
1179  data[0 + TEX_OFFSET] = Source.left() / static_cast<GLfloat>(size.width());
1180  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = (Source.top() + height) / static_cast<GLfloat>(size.height());
1181  data[6 + TEX_OFFSET] = (Source.left() + width) / static_cast<GLfloat>(size.width());
1182  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = Source.top() / static_cast<GLfloat>(size.height());
1183  }
1184  else
1185  {
1186  data[0 + TEX_OFFSET] = Source.left();
1187  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = (Source.top() + height);
1188  data[6 + TEX_OFFSET] = (Source.left() + width);
1189  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = Source.top();
1190  }
1191 
1192  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1193  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1194  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1195  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1196 
1197  width = Texture->m_crop ? std::min(static_cast<int>(width * Scale), Destination.width()) : Destination.width();
1198  height = Texture->m_crop ? std::min(static_cast<int>(height * Scale), Destination.height()) : Destination.height();
1199 
1200  data[2] = data[0] = Destination.left();
1201  data[5] = data[1] = Destination.top();
1202  data[4] = data[6] = Destination.left() + width;
1203  data[3] = data[7] = Destination.top() + height;
1204 
1205  if (Texture->m_rotation != 0)
1206  {
1207  if (Texture->m_rotation == 90)
1208  {
1209  GLfloat temp = data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET];
1210  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET];
1211  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = temp;
1212  data[2 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1213  data[4 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1214  }
1215  else if (Texture->m_rotation == -90)
1216  {
1217  GLfloat temp = data[0 + TEX_OFFSET];
1218  data[0 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1219  data[6 + TEX_OFFSET] = temp;
1220  data[3 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1221  data[5 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1222  }
1223  else if (abs(Texture->m_rotation) == 180)
1224  {
1225  GLfloat temp = data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET];
1226  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET];
1227  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = temp;
1228  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1229  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1230  temp = data[0 + TEX_OFFSET];
1231  data[0 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1232  data[6 + TEX_OFFSET] = temp;
1233  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1234  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1235  }
1236  }
1237 
1238  return true;
1239 }
1240 
1241 GLfloat* MythRenderOpenGL::GetCachedVertices(GLuint Type, const QRect Area)
1242 {
1243  uint64_t ref = (static_cast<uint64_t>(Area.left()) & 0xfff) +
1244  ((static_cast<uint64_t>(Area.top()) & 0xfff) << 12) +
1245  ((static_cast<uint64_t>(Area.width()) & 0xfff) << 24) +
1246  ((static_cast<uint64_t>(Area.height()) & 0xfff) << 36) +
1247  ((static_cast<uint64_t>(Type & 0xfff)) << 48);
1248 
1249  if (m_cachedVertices.contains(ref))
1250  {
1251  m_vertexExpiry.removeOne(ref);
1252  m_vertexExpiry.append(ref);
1253  return m_cachedVertices[ref];
1254  }
1255 
1256  auto *vertices = new GLfloat[8];
1257 
1258  vertices[2] = vertices[0] = Area.left();
1259  vertices[5] = vertices[1] = Area.top();
1260  vertices[4] = vertices[6] = Area.left() + Area.width();
1261  vertices[3] = vertices[7] = Area.top() + Area.height();
1262 
1263  if (Type == GL_LINE_LOOP)
1264  {
1265  vertices[7] = vertices[1];
1266  vertices[5] = vertices[3];
1267  }
1268 
1269  m_cachedVertices.insert(ref, vertices);
1270  m_vertexExpiry.append(ref);
1272 
1273  return vertices;
1274 }
1275 
1277 {
1278  while (m_vertexExpiry.size() > Max)
1279  {
1280  uint64_t ref = m_vertexExpiry.first();
1281  m_vertexExpiry.removeFirst();
1282  GLfloat *vertices = nullptr;
1283  if (m_cachedVertices.contains(ref))
1284  vertices = m_cachedVertices.value(ref);
1285  m_cachedVertices.remove(ref);
1286  delete [] vertices;
1287  }
1288 }
1289 
1290 void MythRenderOpenGL::GetCachedVBO(GLuint Type, const QRect Area)
1291 {
1292  uint64_t ref = (static_cast<uint64_t>(Area.left()) & 0xfff) +
1293  ((static_cast<uint64_t>(Area.top()) & 0xfff) << 12) +
1294  ((static_cast<uint64_t>(Area.width()) & 0xfff) << 24) +
1295  ((static_cast<uint64_t>(Area.height()) & 0xfff) << 36) +
1296  ((static_cast<uint64_t>(Type & 0xfff)) << 48);
1297 
1298  if (m_cachedVBOS.contains(ref))
1299  {
1300  m_vboExpiry.removeOne(ref);
1301  m_vboExpiry.append(ref);
1302  m_cachedVBOS.value(ref)->bind();
1303  return;
1304  }
1305 
1306  GLfloat *vertices = GetCachedVertices(Type, Area);
1307  QOpenGLBuffer *vbo = CreateVBO(kTextureOffset, false);
1308  m_cachedVBOS.insert(ref, vbo);
1309  m_vboExpiry.append(ref);
1310 
1312  {
1313  void* target = vbo->map(QOpenGLBuffer::WriteOnly);
1314  if (target)
1315  memcpy(target, vertices, kTextureOffset);
1316  vbo->unmap();
1317  }
1318  else
1319  {
1320  vbo->write(0, vertices, kTextureOffset);
1321  }
1323 }
1324 
1326 {
1327  while (m_vboExpiry.size() > Max)
1328  {
1329  uint64_t ref = m_vboExpiry.first();
1330  m_vboExpiry.removeFirst();
1331  if (m_cachedVBOS.contains(ref))
1332  {
1333  QOpenGLBuffer *vbo = m_cachedVBOS.value(ref);
1334  delete vbo;
1335  m_cachedVBOS.remove(ref);
1336  }
1337  }
1338 }
1339 
1340 int MythRenderOpenGL::GetBufferSize(QSize Size, QOpenGLTexture::PixelFormat Format, QOpenGLTexture::PixelType Type)
1341 {
1342  int bytes = 0;
1343  int bpp = 0;;
1344 
1345  switch (Format)
1346  {
1347  case QOpenGLTexture::RGBA_Integer:
1348  case QOpenGLTexture::BGRA_Integer:
1349  case QOpenGLTexture::BGRA:
1350  case QOpenGLTexture::RGBA: bpp = 4; break;
1351  case QOpenGLTexture::RGB_Integer:
1352  case QOpenGLTexture::BGR_Integer:
1353  case QOpenGLTexture::BGR:
1354  case QOpenGLTexture::RGB: bpp = 3; break;
1355  case QOpenGLTexture::RG_Integer:
1356  case QOpenGLTexture::RG: bpp = 2; break;
1357  case QOpenGLTexture::Red:
1358  case QOpenGLTexture::Red_Integer:
1359  case QOpenGLTexture::Alpha:
1360  case QOpenGLTexture::Luminance: bpp = 1; break;
1361  default: break; // unsupported
1362  }
1363 
1364  switch (Type)
1365  {
1366  case QOpenGLTexture::Int8: bytes = sizeof(GLbyte); break;
1367  case QOpenGLTexture::UInt8: bytes = sizeof(GLubyte); break;
1368  case QOpenGLTexture::Int16: bytes = sizeof(GLshort); break;
1369  case QOpenGLTexture::UInt16: bytes = sizeof(GLushort); break;
1370  case QOpenGLTexture::Int32: bytes = sizeof(GLint); break;
1371  case QOpenGLTexture::UInt32: bytes = sizeof(GLuint); break;
1372  case QOpenGLTexture::Float32: bytes = sizeof(GLfloat); break;
1373  case QOpenGLTexture::UInt32_RGB10A2: bytes = sizeof(GLuint); break;
1374  default: break; // unsupported
1375  }
1376 
1377  if (!bpp || !bytes || Size.isEmpty())
1378  return 0;
1379 
1380  return Size.width() * Size.height() * bpp * bytes;
1381 }
1382 
1383 void MythRenderOpenGL::PushTransformation(const UIEffects &Fx, QPointF &Center)
1384 {
1385  QMatrix4x4 newtop = m_transforms.top();
1386  if (Fx.m_hzoom != 1.0F || Fx.m_vzoom != 1.0F || Fx.m_angle != 0.0F)
1387  {
1388  newtop.translate(static_cast<GLfloat>(Center.x()), static_cast<GLfloat>(Center.y()));
1389  newtop.scale(Fx.m_hzoom, Fx.m_vzoom);
1390  newtop.rotate(Fx.m_angle, 0, 0, 1);
1391  newtop.translate(static_cast<GLfloat>(-Center.x()), static_cast<GLfloat>(-Center.y()));
1392  }
1393  m_transforms.push(newtop);
1394 }
1395 
1397 {
1398  m_transforms.pop();
1399 }
1400 
1401 inline QOpenGLShaderProgram* ShaderError(QOpenGLShaderProgram *Shader, const QString &Source)
1402 {
1403  QString type = Source.isEmpty() ? "Shader link" : "Shader compile";
1404  LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1 error").arg(type));
1405  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Log:"));
1406  LOG(VB_GENERAL, LOG_ERR, "\n" + Shader->log());
1407  if (!Source.isEmpty())
1408  {
1409  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Source:"));
1410  LOG(VB_GENERAL, LOG_ERR, "\n" + Source);
1411  }
1412  delete Shader;
1413  return nullptr;
1414 }
1415 
1416 QOpenGLShaderProgram *MythRenderOpenGL::CreateShaderProgram(const QString &Vertex, const QString &Fragment)
1417 {
1418  if (!(m_features & Shaders))
1419  return nullptr;
1420 
1421  OpenGLLocker locker(this);
1422  QString vertex = Vertex.isEmpty() ? kDefaultVertexShader : Vertex;
1423  QString fragment = Fragment.isEmpty() ? kDefaultFragmentShader: Fragment;
1424  auto *program = new QOpenGLShaderProgram();
1425  if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex))
1426  return ShaderError(program, vertex);
1427  if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment))
1428  return ShaderError(program, fragment);
1429  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
1430  {
1431  QList<QOpenGLShader*> shaders = program->shaders();
1432  for (QOpenGLShader* shader : std::as_const(shaders))
1433  LOG(VB_GENERAL, LOG_DEBUG, "\n" + shader->sourceCode());
1434  }
1435  program->bindAttributeLocation("a_position", VERTEX_INDEX);
1436  program->bindAttributeLocation("a_color", COLOR_INDEX);
1437  program->bindAttributeLocation("a_texcoord0", TEXTURE_INDEX);
1438  if (!program->link())
1439  return ShaderError(program, "");
1440  return program;
1441 }
1442 
1443 QOpenGLShaderProgram* MythRenderOpenGL::CreateComputeShader(const QString &Source)
1444 {
1445  if (!(m_extraFeaturesUsed & kGLComputeShaders) || Source.isEmpty())
1446  return nullptr;
1447 
1448  OpenGLLocker locker(this);
1449  auto *program = new QOpenGLShaderProgram();
1450  if (!program->addShaderFromSourceCode(QOpenGLShader::Compute, Source))
1451  return ShaderError(program, Source);
1452 
1453  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
1454  {
1455  QList<QOpenGLShader*> shaders = program->shaders();
1456  for (QOpenGLShader* shader : std::as_const(shaders))
1457  LOG(VB_GENERAL, LOG_DEBUG, "\n" + shader->sourceCode());
1458  }
1459 
1460  if (!program->link())
1461  return ShaderError(program, "");
1462  return program;
1463 }
1464 
1465 void MythRenderOpenGL::DeleteShaderProgram(QOpenGLShaderProgram *Program)
1466 {
1467  makeCurrent();
1468  delete Program;
1469  m_cachedMatrixUniforms.clear();
1470  m_activeProgram = nullptr;
1471  m_cachedUniformLocations.remove(Program);
1472  doneCurrent();
1473 }
1474 
1475 bool MythRenderOpenGL::EnableShaderProgram(QOpenGLShaderProgram* Program)
1476 {
1477  if (!Program)
1478  return false;
1479 
1480  if (m_activeProgram == Program)
1481  return true;
1482 
1483  makeCurrent();
1484  Program->bind();
1485  m_activeProgram = Program;
1486  doneCurrent();
1487  return true;
1488 }
1489 
1490 void MythRenderOpenGL::SetShaderProjection(QOpenGLShaderProgram *Program)
1491 {
1492  if (Program)
1493  {
1494  SetShaderProgramParams(Program, m_projection, "u_projection");
1495  SetShaderProgramParams(Program, m_transforms.top(), "u_transform");
1496  }
1497 }
1498 
1499 void MythRenderOpenGL::SetShaderProgramParams(QOpenGLShaderProgram *Program, const QMatrix4x4 &Value, const char *Uniform)
1500 {
1501  OpenGLLocker locker(this);
1502  if (!Uniform || !EnableShaderProgram(Program))
1503  return;
1504 
1505  // Uniform value cacheing
1506  QString tag = QString("%1-%2").arg(Program->programId()).arg(Uniform);
1507  QHash<QString,QMatrix4x4>::iterator it = m_cachedMatrixUniforms.find(tag);
1508  if (it == m_cachedMatrixUniforms.end())
1509  m_cachedMatrixUniforms.insert(tag, Value);
1510  else if (!qFuzzyCompare(Value, it.value()))
1511  it.value() = Value;
1512  else
1513  return;
1514 
1515  // Uniform location cacheing
1516  QByteArray uniform(Uniform);
1517  GLint location = 0;
1518  QHash<QByteArray, GLint> &uniforms = m_cachedUniformLocations[Program];
1519  if (uniforms.contains(uniform))
1520  {
1521  location = uniforms[uniform];
1522  }
1523  else
1524  {
1525  location = Program->uniformLocation(Uniform);
1526  uniforms.insert(uniform, location);
1527  }
1528 
1529  Program->setUniformValue(location, Value);
1530 }
1531 
1533 {
1540 }
1541 
1543 {
1544  for (auto & program : m_defaultPrograms)
1545  {
1546  DeleteShaderProgram(program);
1547  program = nullptr;
1548  }
1549 }
1550 
1552 {
1553  m_projection.setToIdentity();
1554  m_projection.ortho(m_viewport);
1555 }
1556 
1557 std::tuple<int, int, int> MythRenderOpenGL::GetGPUMemory()
1558 {
1559  OpenGLLocker locker(this);
1561  {
1562  GLint total = 0;
1563  GLint dedicated = 0;
1564  GLint available = 0;
1565  glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total);
1566  glGetIntegerv(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated);
1567  glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &available);
1568  return { total / 1024, dedicated / 1024, available / 1024 };
1569  }
1570  return { 0, 0, 0 };
1571 }
1572 
1584 {
1585  OpenGLLocker locker(this);
1586  QSize size{256, 256};
1587  QOpenGLFramebufferObject *fbo = CreateFramebuffer(size, true);
1588  if (fbo)
1589  {
1591  delete fbo;
1592  }
1593 }
MythRenderOpenGL::Init
bool Init(void)
Definition: mythrenderopengl.cpp:210
Source
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:134
TEXTURE_SIZE
static constexpr GLint TEXTURE_SIZE
Definition: mythrenderopengl.cpp:35
MythGLTexture::m_source
QRect m_source
Definition: mythrenderopengl.h:74
MYTH_GLMAPBUFFERPROC
GLvoid *(APIENTRY *)(GLenum target, GLenum access) MYTH_GLMAPBUFFERPROC
Definition: mythrenderopengldefs.h:37
MythGLTexture::m_flip
bool m_flip
Definition: mythrenderopengl.h:72
MythRenderOpenGL::m_features
QOpenGLFunctions::OpenGLFeatures m_features
Definition: mythrenderopengl.h:223
UIEffects::m_angle
float m_angle
Definition: mythuianimation.h:42
MythGLTexture
Definition: mythrenderopengl.h:56
mythrenderopenglshaders.h
kGLNVMemory
@ kGLNVMemory
Definition: mythrenderopengl.h:48
MythRenderOpenGL::SetBackground
void SetBackground(uint8_t Red, uint8_t Green, uint8_t Blue, uint8_t Alpha)
Definition: mythrenderopengl.cpp:618
LOC
#define LOC
Definition: mythrenderopengl.cpp:24
MythRenderOpenGL::IsReady
bool IsReady(void)
Definition: mythrenderopengl.cpp:506
MythGLTexture::m_texture
QOpenGLTexture * m_texture
Definition: mythrenderopengl.h:66
MythRenderOpenGL::GetMaxTextureSize
int GetMaxTextureSize(void) const
Definition: mythrenderopengl.cpp:445
MythGLTexture::m_vertexData
std::array< GLfloat, 16 > m_vertexData
Definition: mythrenderopengl.h:76
MythRenderOpenGL::DeleteFramebuffer
void DeleteFramebuffer(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:775
MythRenderOpenGL::~MythRenderOpenGL
~MythRenderOpenGL() override
Definition: mythrenderopengl.cpp:135
MythGLTexture::m_destination
QRect m_destination
Definition: mythrenderopengl.h:75
MythRenderOpenGL::DebugFeatures
void DebugFeatures(void)
Definition: mythrenderopengl.cpp:399
MythRenderOpenGL::ClearFramebuffer
void ClearFramebuffer(void)
Definition: mythrenderopengl.cpp:805
MythRenderOpenGL::CreateComputeShader
QOpenGLShaderProgram * CreateComputeShader(const QString &Source)
Definition: mythrenderopengl.cpp:1443
MythRenderOpenGL::ExpireVertices
void ExpireVertices(int Max=0)
Definition: mythrenderopengl.cpp:1276
MythRenderOpenGL::ClearRect
void ClearRect(QOpenGLFramebufferObject *Target, QRect Area, int Color, int Alpha)
An optimised method to clear a QRect to the given color.
Definition: mythrenderopengl.cpp:959
kSimpleFragmentShader
static const QString kSimpleFragmentShader
Definition: mythrenderopenglshaders.h:49
MAX_VERTEX_CACHE
static constexpr int MAX_VERTEX_CACHE
Definition: mythrenderopengl.cpp:40
MythRenderOpenGL::m_cachedVBOS
QMap< uint64_t, QOpenGLBuffer * > m_cachedVBOS
Definition: mythrenderopengl.h:215
MythRenderOpenGL::m_fullRange
bool m_fullRange
Definition: mythrenderopengl.h:235
MythEGL::GetEGLDisplay
void * GetEGLDisplay(void)
Definition: mythegl.cpp:76
MythRenderOpenGL::m_maxTextureUnits
int m_maxTextureUnits
Definition: mythrenderopengl.h:227
MythMainWindow::getMainWindow
static MythMainWindow * getMainWindow(bool UseDB=true)
Return the existing main window, or create one.
Definition: mythmainwindow.cpp:80
MythRenderOpenGL::m_activeFramebuffer
GLuint m_activeFramebuffer
Definition: mythrenderopengl.h:203
MythRenderOpenGL::m_maxTextureSize
int m_maxTextureSize
Definition: mythrenderopengl.h:226
MythGLTexture::m_crop
bool m_crop
Definition: mythrenderopengl.h:73
MythRenderOpenGL::GetProcAddress
QFunctionPointer GetProcAddress(const QString &Proc) const
Definition: mythrenderopengl.cpp:1084
MythGLTexture::m_data
unsigned char * m_data
Definition: mythrenderopengl.h:63
MythRenderOpenGL::logDebugMarker
void logDebugMarker(const QString &Message)
Definition: mythrenderopengl.cpp:193
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
MythRenderOpenGL::m_blend
bool m_blend
Definition: mythrenderopengl.h:233
OpenGLLocker::~OpenGLLocker
~OpenGLLocker()
Definition: mythrenderopengl.cpp:59
MythRenderOpenGL::PushTransformation
void PushTransformation(const UIEffects &Fx, QPointF &Center)
Definition: mythrenderopengl.cpp:1383
kRenderOpenGL
@ kRenderOpenGL
Definition: mythrender_base.h:19
MythRenderOpenGL::m_parameters
QMatrix4x4 m_parameters
Definition: mythrenderopengl.h:238
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
MythDate::Format
Format
Definition: mythdate.h:15
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX
#define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX
Definition: mythrenderopengldefs.h:33
kGLLegacyTextures
@ kGLLegacyTextures
Definition: mythrenderopengl.h:47
MythRenderOpenGL::ExpireVBOS
void ExpireVBOS(int Max=0)
Definition: mythrenderopengl.cpp:1325
MythRenderOpenGL::m_vertexExpiry
QList< uint64_t > m_vertexExpiry
Definition: mythrenderopengl.h:214
kLimitedRangeOffset
static const float kLimitedRangeOffset
Definition: mythrenderopengl.cpp:955
MythMainWindow::GetRenderDevice
MythRender * GetRenderDevice()
Definition: mythmainwindow.cpp:292
HasMythMainWindow
bool HasMythMainWindow(void)
Definition: mythmainwindow.cpp:109
kGLExtRects
@ kGLExtRects
Definition: mythrenderopengl.h:44
kGLExtSubimage
@ kGLExtSubimage
Definition: mythrenderopengl.h:45
GLYesNo
static constexpr QLatin1String GLYesNo(bool v)
Definition: mythrenderopengl.cpp:394
MythRenderOpenGL::CreateFramebufferTexture
MythGLTexture * CreateFramebufferTexture(QOpenGLFramebufferObject *Framebuffer)
This is no longer used but will probably be needed for future UI enhancements.
Definition: mythrenderopengl.cpp:763
MythRenderOpenGL::m_lock
QRecursiveMutex m_lock
Definition: mythrenderopengl.h:219
MythRenderOpenGL::kVertexSize
static constexpr GLuint kVertexSize
Definition: mythrenderopengl.h:129
MythRenderOpenGL::GetTextureDataSize
static int GetTextureDataSize(MythGLTexture *Texture)
Definition: mythrenderopengl.cpp:672
true
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:95
MythRenderOpenGL::m_background
int32_t m_background
Definition: mythrenderopengl.h:234
kDrawVertexShader
static const QString kDrawVertexShader
Definition: mythrenderopenglshaders.h:56
MythRenderOpenGL::GetFeatures
QOpenGLFunctions::OpenGLFeatures GetFeatures(void) const
Definition: mythrenderopengl.cpp:460
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
MythGLTexture::m_rotation
int m_rotation
Definition: mythrenderopengl.h:78
MythRenderOpenGL::SetShaderProgramParams
void SetShaderProgramParams(QOpenGLShaderProgram *Program, const QMatrix4x4 &Value, const char *Uniform)
Definition: mythrenderopengl.cpp:1499
MythRenderOpenGL::m_ready
bool m_ready
Definition: mythrenderopengl.h:200
OpenGLLocker::m_render
MythRenderOpenGL * m_render
Definition: mythrenderopengl.h:261
MythRenderOpenGL::m_transforms
QStack< QMatrix4x4 > m_transforms
Definition: mythrenderopengl.h:237
kTextureOffset
static constexpr GLuint kTextureOffset
Definition: mythrenderopengl.cpp:38
MythRenderOpenGL::m_activeProgram
QOpenGLShaderProgram * m_activeProgram
Definition: mythrenderopengl.h:210
kRoundedRectShader
static const QString kRoundedRectShader
Definition: mythrenderopenglshaders.h:75
MythRenderOpenGL::m_flushEnabled
bool m_flushEnabled
Definition: mythrenderopengl.h:245
mythrenderopengl.h
MythRenderOpenGL::m_cachedUniformLocations
QHash< QOpenGLShaderProgram *, QHash< QByteArray, GLint > > m_cachedUniformLocations
Definition: mythrenderopengl.h:240
kDefaultVertexShader
static const QString kDefaultVertexShader
Definition: mythrenderopenglshaders.h:6
COLOR_INDEX
static constexpr GLuint COLOR_INDEX
Definition: mythrenderopengl.cpp:32
MythRenderOpenGL::Check16BitFBO
void Check16BitFBO(void)
Check for 16bit framebufferobject support.
Definition: mythrenderopengl.cpp:1583
MythRenderOpenGL::m_extraFeaturesUsed
int m_extraFeaturesUsed
Definition: mythrenderopengl.h:225
mythlogging.h
kGL16BitFBO
@ kGL16BitFBO
Definition: mythrenderopengl.h:49
Source
Definition: channelsettings.cpp:93
MythGLTexture::m_vbo
QOpenGLBuffer * m_vbo
Definition: mythrenderopengl.h:69
MythRenderOpenGL::CreateTextureFromQImage
MythGLTexture * CreateTextureFromQImage(QImage *Image)
Definition: mythrenderopengl.cpp:630
MythFile::copy
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
Definition: mythmiscutil.cpp:263
MythRenderOpenGL::m_vboExpiry
QList< uint64_t > m_vboExpiry
Definition: mythrenderopengl.h:216
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
MythRenderOpenGL::glVertexAttribPointerI
void glVertexAttribPointerI(GLuint Index, GLint Size, GLenum Type, GLboolean Normalize, GLsizei Stride, GLuint Value)
Definition: mythrenderopengl.cpp:1060
debug
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
MythRenderOpenGL::PopTransformation
void PopTransformation(void)
Definition: mythrenderopengl.cpp:1396
ShaderError
QOpenGLShaderProgram * ShaderError(QOpenGLShaderProgram *Shader, const QString &Source)
Definition: mythrenderopengl.cpp:1401
MythRenderOpenGL::swapBuffers
void swapBuffers()
Definition: mythrenderopengl.cpp:511
kGLGeometryShaders
@ kGLGeometryShaders
Definition: mythrenderopengl.h:51
MythRenderOpenGL::makeCurrent
void makeCurrent()
Definition: mythrenderopengl.cpp:566
MythXDisplay::DisplayIsRemote
static bool DisplayIsRemote()
Determine if we are running a remote X11 session.
Definition: mythxdisplay.cpp:43
MythRenderOpenGL::DeleteTexture
void DeleteTexture(MythGLTexture *Texture)
Definition: mythrenderopengl.cpp:716
MythRenderOpenGL::GetDescription
QStringList GetDescription(void) override
Definition: mythrenderopengl.cpp:1143
MythEGL::IsEGL
bool IsEGL(void)
Definition: mythegl.cpp:29
MythRenderOpenGL::DrawProcedural
void DrawProcedural(QRect Area, int Alpha, QOpenGLFramebufferObject *Target, QOpenGLShaderProgram *Program, float TimeVal)
Definition: mythrenderopengl.cpp:812
MythRenderOpenGL::DrawRoundRect
void DrawRoundRect(QOpenGLFramebufferObject *Target, QRect Area, int CornerRadius, const QBrush &FillBrush, const QPen &LinePen, int Alpha)
Definition: mythrenderopengl.cpp:987
MythRenderOpenGL::GetExtraFeatures
int GetExtraFeatures(void) const
Definition: mythrenderopengl.cpp:455
GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
#define GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
Definition: mythrenderopengldefs.h:25
kShaderEdge
@ kShaderEdge
Definition: mythrenderopengl.h:89
MythRenderOpenGL::DeleteShaderProgram
void DeleteShaderProgram(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1465
MythRenderOpenGL::MessageLogged
void MessageLogged(const QOpenGLDebugMessage &Message)
Definition: mythrenderopengl.cpp:145
MythRenderOpenGL::CreateVBO
QOpenGLBuffer * CreateVBO(int Size, bool Release=true)
Definition: mythrenderopengl.cpp:1099
uint
unsigned int uint
Definition: compat.h:81
MythRenderOpenGL::CreateDefaultShaders
bool CreateDefaultShaders(void)
Definition: mythrenderopengl.cpp:1532
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
kGLBufferMap
@ kGLBufferMap
Definition: mythrenderopengl.h:43
kSimpleVertexShader
static const QString kSimpleVertexShader
Definition: mythrenderopenglshaders.h:38
TEXTURE_INDEX
static constexpr GLuint TEXTURE_INDEX
Definition: mythrenderopengl.cpp:33
VERTEX_INDEX
static constexpr GLuint VERTEX_INDEX
Definition: mythrenderopengl.cpp:31
kLimitedRangeScale
static const float kLimitedRangeScale
Definition: mythrenderopengl.cpp:956
MythGLTexture::m_bufferSize
int m_bufferSize
Definition: mythrenderopengl.h:64
TEX_OFFSET
static constexpr size_t TEX_OFFSET
Definition: mythrenderopengl.h:54
MythRenderOpenGL::SetBlend
void SetBlend(bool Enable)
Definition: mythrenderopengl.cpp:607
OpenGLLocker::OpenGLLocker
OpenGLLocker(MythRenderOpenGL *Render)
Definition: mythrenderopengl.cpp:52
kShaderSimple
@ kShaderSimple
Definition: mythrenderopengl.h:86
MythRenderOpenGL::ActiveTexture
void ActiveTexture(GLuint ActiveTex)
Definition: mythrenderopengl.cpp:702
MythRenderOpenGL::m_window
QWindow * m_window
Definition: mythrenderopengl.h:252
mythxdisplay.h
MythGLTexture::m_target
GLenum m_target
Definition: mythrenderopengl.h:77
MythRenderOpenGL::doneCurrent
void doneCurrent()
Definition: mythrenderopengl.cpp:574
MythRenderOpenGL::GetMaxTextureUnits
int GetMaxTextureUnits(void) const
Definition: mythrenderopengl.cpp:450
GL_TEXTURE0
#define GL_TEXTURE0
Definition: mythrenderopengldefs.h:9
MythRenderOpenGL
Definition: mythrenderopengl.h:96
MythEGL
Definition: mythegl.h:17
UIEffects::m_vzoom
float m_vzoom
Definition: mythuianimation.h:41
MythRenderOpenGL::m_activeTexture
GLuint m_activeTexture
Definition: mythrenderopengl.h:232
MythRenderOpenGL::m_projection
QMatrix4x4 m_projection
Definition: mythrenderopengl.h:236
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
MythRenderOpenGL::BindFramebuffer
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:785
MythRenderOpenGL::GetSwapCount
uint64_t GetSwapCount()
Definition: mythrenderopengl.cpp:517
kShaderRect
@ kShaderRect
Definition: mythrenderopengl.h:88
MythGLTexture::m_textureId
GLuint m_textureId
Definition: mythrenderopengl.h:65
mythcorecontext.h
MythRenderOpenGL::m_cachedMatrixUniforms
QHash< QString, QMatrix4x4 > m_cachedMatrixUniforms
Definition: mythrenderopengl.h:239
MythRender
Definition: mythrender_base.h:23
MythRenderOpenGL::m_extraFeatures
int m_extraFeatures
Definition: mythrenderopengl.h:224
MythRenderOpenGL::SetMatrixView
void SetMatrixView(void)
Definition: mythrenderopengl.cpp:1551
GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
#define GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
Definition: mythrenderopengldefs.h:29
MythRenderOpenGL::m_openGLDebuggerFilter
QOpenGLDebugMessage::Types m_openGLDebuggerFilter
Definition: mythrenderopengl.h:251
MythRenderOpenGL::GetCachedVBO
void GetCachedVBO(GLuint Type, QRect Area)
Definition: mythrenderopengl.cpp:1290
MythGLTexture::m_size
QSize m_size
Definition: mythrenderopengl.h:70
MythRenderOpenGL::Create
static MythRenderOpenGL * Create(QWidget *Widget)
Definition: mythrenderopengl.cpp:81
MythRenderOpenGL::CreateFramebuffer
QOpenGLFramebufferObject * CreateFramebuffer(QSize &Size, bool SixteenBit=false)
Definition: mythrenderopengl.cpp:731
MythRenderOpenGL::m_vao
GLuint m_vao
Definition: mythrenderopengl.h:241
MythRenderOpenGL::SetTextureFilters
void SetTextureFilters(MythGLTexture *Texture, QOpenGLTexture::Filter Filter, QOpenGLTexture::WrapMode Wrap=QOpenGLTexture::ClampToEdge)
Definition: mythrenderopengl.cpp:679
MythRenderOpenGL::m_swapCount
uint64_t m_swapCount
Definition: mythrenderopengl.h:230
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:65
kDefaultFragmentShader
static const QString kDefaultFragmentShader
Definition: mythrenderopenglshaders.h:20
kVertexOffset
static constexpr GLuint kVertexOffset
Definition: mythrenderopengl.cpp:37
MythRenderOpenGL::DeleteDefaultShaders
void DeleteDefaultShaders(void)
Definition: mythrenderopengl.cpp:1542
UIEffects
Definition: mythuianimation.h:13
MythRenderOpenGL::MythRenderOpenGL
MythRenderOpenGL(const QSurfaceFormat &Format, QWidget *Widget)
Definition: mythrenderopengl.cpp:122
kGLComputeShaders
@ kGLComputeShaders
Definition: mythrenderopengl.h:50
MythRenderOpenGL::Init2DState
void Init2DState(void)
Definition: mythrenderopengl.cpp:1069
VERTEX_SIZE
static constexpr GLint VERTEX_SIZE
Definition: mythrenderopengl.cpp:34
MythRenderOpenGL::UpdateTextureVertices
static bool UpdateTextureVertices(MythGLTexture *Texture, QRect Source, QRect Destination, int Rotation, qreal Scale=1.0)
Definition: mythrenderopengl.cpp:1157
MythRender::Type
RenderType Type(void) const
Definition: mythrender_base.h:32
MythRenderOpenGL::SetViewPort
void SetViewPort(QRect Rect, bool ViewportOnly=false) override
Definition: mythrenderopengl.cpp:584
MythRenderOpenGL::ReleaseResources
void ReleaseResources(void) override
Definition: mythrenderopengl.cpp:1116
MythRenderOpenGL::GetCachedVertices
GLfloat * GetCachedVertices(GLuint Type, QRect Area)
Definition: mythrenderopengl.cpp:1241
UIEffects::m_hzoom
float m_hzoom
Definition: mythuianimation.h:40
MythRenderOpenGL::m_lockLevel
int m_lockLevel
Definition: mythrenderopengl.h:220
MythGLTexture::MythGLTexture
MythGLTexture(QOpenGLTexture *Texture)
Definition: mythrenderopengl.cpp:42
MYTH_GLUNMAPBUFFERPROC
GLboolean(APIENTRY *)(GLenum target) MYTH_GLUNMAPBUFFERPROC
Definition: mythrenderopengldefs.h:38
kDefaultFragmentShaderLimited
static const QString kDefaultFragmentShaderLimited
Definition: mythrenderopenglshaders.h:29
MythRenderOpenGL::GetTextureSize
QSize GetTextureSize(QSize Size, bool Normalised)
Definition: mythrenderopengl.cpp:658
MythRenderOpenGL::GetBufferSize
static int GetBufferSize(QSize Size, QOpenGLTexture::PixelFormat Format, QOpenGLTexture::PixelType Type)
Definition: mythrenderopengl.cpp:1340
MythRenderOpenGL::IsRecommendedRenderer
bool IsRecommendedRenderer(void)
Definition: mythrenderopengl.cpp:465
MythRenderOpenGL::m_viewport
QRect m_viewport
Definition: mythrenderopengl.h:231
mythmainwindow.h
MythRenderOpenGL::GetGPUMemory
std::tuple< int, int, int > GetGPUMemory()
Definition: mythrenderopengl.cpp:1557
kGLTiled
@ kGLTiled
Definition: mythrenderopengl.h:46
MythRenderOpenGL::contextToBeDestroyed
void contextToBeDestroyed(void)
Definition: mythrenderopengl.cpp:205
MythRenderOpenGL::m_openglDebugger
QOpenGLDebugLogger * m_openglDebugger
Definition: mythrenderopengl.h:250
MythRenderOpenGL::SetShaderProjection
void SetShaderProjection(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1490
MythRenderOpenGL::m_cachedVertices
QMap< uint64_t, GLfloat * > m_cachedVertices
Definition: mythrenderopengl.h:213
MythRenderOpenGL::m_defaultPrograms
std::array< QOpenGLShaderProgram *, kShaderCount > m_defaultPrograms
Definition: mythrenderopengl.h:209
MythMainWindow
Definition: mythmainwindow.h:28
kRoundedEdgeShader
static const QString kRoundedEdgeShader
Definition: mythrenderopenglshaders.h:87
Color
Definition: graphic.h:6
kShaderDefault
@ kShaderDefault
Definition: mythrenderopengl.h:87
MythRenderOpenGL::SetWidget
void SetWidget(QWidget *Widget)
Definition: mythrenderopengl.cpp:524
mythuitype.h
MythRenderOpenGL::CreateShaderProgram
QOpenGLShaderProgram * CreateShaderProgram(const QString &Vertex, const QString &Fragment)
Definition: mythrenderopengl.cpp:1416
MythRenderOpenGL::EnableShaderProgram
bool EnableShaderProgram(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1475
OpenGLLocker
Definition: mythrenderopengl.h:255