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