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").arg(source).arg(type).arg(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  // RGBA16 - available on ES via extension
313  m_extraFeatures |= isOpenGLES() ? hasExtension("GL_EXT_texture_norm16") ? kGLExtRGBA16 : kGLFeatNone : kGLExtRGBA16;
314 
315  // Pixel buffer objects
316  bool buffer_procs = reinterpret_cast<MYTH_GLMAPBUFFERPROC>(GetProcAddress("glMapBuffer")) &&
317  reinterpret_cast<MYTH_GLUNMAPBUFFERPROC>(GetProcAddress("glUnmapBuffer"));
318 
319  // Buffers are available by default (GL and GLES).
320  // Buffer mapping is available by extension
321  if ((isOpenGLES() && hasExtension("GL_OES_mapbuffer") && buffer_procs) ||
322  (hasExtension("GL_ARB_vertex_buffer_object") && buffer_procs))
324 
325  // Rectangular textures
326  if (!isOpenGLES() && (hasExtension("GL_NV_texture_rectangle") ||
327  hasExtension("GL_ARB_texture_rectangle") ||
328  hasExtension("GL_EXT_texture_rectangle")))
330 
331  // GL_RED etc texure formats. Not available on GLES2.0 or GL < 2
332  if ((isOpenGLES() && format().majorVersion() < 3) ||
333  (!isOpenGLES() && format().majorVersion() < 2))
335 
336  // GL_UNPACK_ROW_LENGTH - for uploading video textures
337  // Note: Should also be available on GL1.4 per specification
338  if (!isOpenGLES() || (isOpenGLES() && ((fmt.majorVersion() >= 3) || hasExtension("GL_EXT_unpack_subimage"))))
340 
341  // check for core profile N.B. not OpenGL ES
342  if (fmt.profile() == QSurfaceFormat::OpenGLContextProfile::CoreProfile)
343  {
344  // if we have a core profile then we need a VAO bound - this is just a
345  // workaround for the time being
346  extraFunctions()->glGenVertexArrays(1, &m_vao);
347  extraFunctions()->glBindVertexArray(m_vao);
348  }
349 
350  // For (embedded) GPUs that use tile based rendering, it is faster to use
351  // glClear e.g. on the Pi3 it improves video frame rate significantly. Using
352  // glClear tells the GPU it doesn't have to retrieve the old framebuffer and will
353  // also clear existing draw calls.
354  // For now this just includes Broadcom VideoCoreIV.
355  // Other Tile Based Deferred Rendering GPUS - PowerVR5/6/7, Apple (PowerVR as well?)
356  // Other Tile Based Immediate Mode Rendering GPUS - ARM Mali, Qualcomm Adreno
357  static const std::array<const QByteArray,3> kTiled { "videocore", "vc4", "v3d" };
358  auto renderer = QByteArray(reinterpret_cast<const char*>(glGetString(GL_RENDERER))).toLower();
359  for (const auto & name : kTiled)
360  {
361  if (renderer.contains(name))
362  {
364  break;
365  }
366  }
367 
368  // Check for memory extensions
369  if (hasExtension("GL_NVX_gpu_memory_info"))
371 
372  // Check 16 bit FBOs
373  Check16BitFBO();
374 
375  // Check for compute and geometry shaders
376  if (QOpenGLShader::hasOpenGLShaders(QOpenGLShader::Compute))
378  if (QOpenGLShader::hasOpenGLShaders(QOpenGLShader::Geometry))
380 
381  DebugFeatures();
382 
384  if (!CreateDefaultShaders())
385  {
386  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create default shaders");
387  return false;
388  }
389 
390  LOG(VB_GENERAL, LOG_INFO, LOC + "Initialised MythRenderOpenGL");
391  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using %1 range output").arg(m_fullRange ? "full" : "limited"));
392  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
393  logDebugMarker("RENDER_INIT_END");
394  return true;
395 }
396 
397 #define GLYesNo(arg) ((arg) ? "Yes" : "No")
398 
400 {
401  static bool s_debugged = false;
402  if (s_debugged)
403  return;
404  s_debugged = true;
405  QSurfaceFormat fmt = format();
406  QString qtglversion = QString("OpenGL%1 %2.%3")
407  .arg(fmt.renderableType() == QSurfaceFormat::OpenGLES ? "ES" : "")
408  .arg(fmt.majorVersion()).arg(fmt.minorVersion());
409  QString qtglsurface = QString("RGBA: %1%2%3%4 Depth: %5 Stencil: %6")
410  .arg(fmt.redBufferSize()).arg(fmt.greenBufferSize())
411  .arg(fmt.greenBufferSize()).arg(fmt.alphaBufferSize())
412  .arg(fmt.depthBufferSize()).arg(fmt.stencilBufferSize());
413  QStringList shaders {"None"};
414  if (m_features & Shaders)
415  {
416  shaders = QStringList { "Vertex", "Fragment" };
418  shaders << "Geometry";
420  shaders << "Compute";
421  }
422  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL vendor : %1").arg(reinterpret_cast<const char*>(glGetString(GL_VENDOR))));
423  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL renderer : %1").arg(reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
424  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL version : %1").arg(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
425  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt platform : %1").arg(QGuiApplication::platformName()));
426 #ifdef USING_EGL
427  bool eglfuncs = IsEGL();
428  LOG(VB_GENERAL, LOG_INFO, LOC + QString("EGL display : %1").arg(GLYesNo(GetEGLDisplay() != nullptr)));
429  LOG(VB_GENERAL, LOG_INFO, LOC + QString("EGL images : %1").arg(GLYesNo(eglfuncs)));
430 #endif
431  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt OpenGL format : %1").arg(qtglversion));
432  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt OpenGL surface : %1").arg(qtglsurface));
433  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture size : %1").arg(m_maxTextureSize));
434  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture units : %1").arg(m_maxTextureUnits));
435  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Shaders : %1").arg(shaders.join(",")));
436  LOG(VB_GENERAL, LOG_INFO, LOC + QString("NPOT textures : %1").arg(GLYesNo(m_features & NPOTTextures)));
437  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Multitexturing : %1").arg(GLYesNo(m_features & Multitexture)));
438  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Rectangular textures : %1").arg(GLYesNo(m_extraFeatures & kGLExtRects)));
439  //LOG(VB_GENERAL, LOG_INFO, LOC + QString("RGBA16 textures : %1").arg(GLYesNo(m_extraFeatures & kGLExtRGBA16)));
440  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Buffer mapping : %1").arg(GLYesNo(m_extraFeatures & kGLBufferMap)));
441  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Framebuffer objects : %1").arg(GLYesNo(m_features & Framebuffers)));
442  LOG(VB_GENERAL, LOG_INFO, LOC + QString("16bit framebuffers : %1").arg(GLYesNo(m_extraFeatures & kGL16BitFBO)));
443  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Unpack Subimage : %1").arg(GLYesNo(m_extraFeatures & kGLExtSubimage)));
444  LOG(VB_GENERAL, LOG_INFO, LOC + QString("GL_RED/GL_R8 : %1").arg(GLYesNo(!(m_extraFeatures & kGLLegacyTextures))));
445 
446  // warnings
447  if (m_maxTextureUnits < 3)
448  LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning: Insufficient texture units for some features.");
449 }
450 
452 {
453  return m_maxTextureSize;
454 }
455 
457 {
458  return m_maxTextureUnits;
459 }
460 
462 {
463  return m_extraFeaturesUsed;
464 }
465 
466 QOpenGLFunctions::OpenGLFeatures MythRenderOpenGL::GetFeatures(void) const
467 {
468  return m_features;
469 }
470 
472 {
473  if (!IsReady())
474  return false;
475 
476  bool recommended = true;
477  OpenGLLocker locker(this);
478  QString renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
479 
480  if (!(openGLFeatures() & Shaders))
481  {
482  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL has no shader support");
483  recommended = false;
484  }
485  else if (!(openGLFeatures() & Framebuffers))
486  {
487  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL has no framebuffer support");
488  recommended = false;
489  }
490  else if (renderer.contains("Software Rasterizer", Qt::CaseInsensitive))
491  {
492  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL is using software rasterizer.");
493  recommended = false;
494  }
495  else if (renderer.contains("softpipe", Qt::CaseInsensitive))
496  {
497  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL seems to be using software "
498  "fallback. Please check your OpenGL driver installation, "
499  "configuration, and device permissions.");
500  recommended = false;
501  }
502 
503  if (!recommended)
504  {
505  LOG(VB_GENERAL, LOG_INFO, LOC +
506  "OpenGL not recommended with this system's hardware/drivers.");
507  }
508 
509  return recommended;
510 }
511 
513 {
514  return isValid() && m_ready;
515 }
516 
518 {
519  QOpenGLContext::swapBuffers(m_window);
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 
760 MythGLTexture* MythRenderOpenGL::CreateFramebufferTexture(QOpenGLFramebufferObject *Framebuffer)
761 {
762  if (!Framebuffer)
763  return nullptr;
764 
765  auto *texture = new MythGLTexture(Framebuffer->texture());
766  texture->m_size = texture->m_totalSize = Framebuffer->size();
767  texture->m_vbo = CreateVBO(kVertexSize);
768  texture->m_flip = false;
769  return texture;
770 }
771 
772 void MythRenderOpenGL::DeleteFramebuffer(QOpenGLFramebufferObject *Framebuffer)
773 {
774  if (Framebuffer)
775  {
776  makeCurrent();
777  delete Framebuffer;
778  doneCurrent();
779  }
780 }
781 
782 void MythRenderOpenGL::BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
783 {
784  if ((Framebuffer && Framebuffer->handle() == m_activeFramebuffer) ||
785  (!Framebuffer && defaultFramebufferObject() == m_activeFramebuffer))
786  return;
787 
788  makeCurrent();
789  if (Framebuffer == nullptr)
790  {
791  QOpenGLFramebufferObject::bindDefault();
792  m_activeFramebuffer = defaultFramebufferObject();
793  }
794  else
795  {
796  Framebuffer->bind();
797  m_activeFramebuffer = Framebuffer->handle();
798  }
799  doneCurrent();
800 }
801 
803 {
804  makeCurrent();
805  glClear(GL_COLOR_BUFFER_BIT);
806  doneCurrent();
807 }
808 
809 void MythRenderOpenGL::DrawBitmap(MythGLTexture *Texture, QOpenGLFramebufferObject *Target,
810  const QRect Source, const QRect Destination,
811  QOpenGLShaderProgram *Program, int Alpha, qreal Scale)
812 {
813  makeCurrent();
814 
815  if (!Texture || !((Texture->m_texture || Texture->m_textureId) && Texture->m_vbo))
816  return;
817 
818  if (Program == nullptr)
820 
821  BindFramebuffer(Target);
822  SetShaderProjection(Program);
823 
824  GLenum textarget = Texture->m_target;
825  Program->setUniformValue("s_texture0", 0);
827  if (Texture->m_texture)
828  Texture->m_texture->bind();
829  else
830  glBindTexture(textarget, Texture->m_textureId);
831 
832  QOpenGLBuffer* buffer = Texture->m_vbo;
833  buffer->bind();
834  if (UpdateTextureVertices(Texture, Source, Destination, 0, Scale))
835  {
837  {
838  void* target = buffer->map(QOpenGLBuffer::WriteOnly);
839  if (target)
840  {
841  std::copy(Texture->m_vertexData.cbegin(),
842  Texture->m_vertexData.cend(),
843  static_cast<GLfloat*>(target));
844  }
845  buffer->unmap();
846  }
847  else
848  {
849  buffer->write(0, Texture->m_vertexData.data(), kVertexSize);
850  }
851  }
852 
853  glEnableVertexAttribArray(VERTEX_INDEX);
854  glEnableVertexAttribArray(TEXTURE_INDEX);
855  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
856  glVertexAttrib4f(COLOR_INDEX, 1.0F, 1.0F, 1.0F, Alpha / 255.0F);
857  glVertexAttribPointerI(TEXTURE_INDEX, TEXTURE_SIZE, GL_FLOAT, GL_FALSE, TEXTURE_SIZE * sizeof(GLfloat), kTextureOffset);
858  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
859  glDisableVertexAttribArray(TEXTURE_INDEX);
860  glDisableVertexAttribArray(VERTEX_INDEX);
861  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
862  doneCurrent();
863 }
864 
865 void MythRenderOpenGL::DrawBitmap(std::vector<MythGLTexture *> &Textures,
866  QOpenGLFramebufferObject *Target,
867  const QRect Source, const QRect Destination,
868  QOpenGLShaderProgram *Program,
869  int Rotation)
870 {
871  if (Textures.empty())
872  return;
873 
874  makeCurrent();
875  BindFramebuffer(Target);
876 
877  if (Program == nullptr)
879 
880  MythGLTexture* first = Textures[0];
881  if (!first || !((first->m_texture || first->m_textureId) && first->m_vbo))
882  return;
883 
884  SetShaderProjection(Program);
885 
886  GLenum textarget = first->m_target;
887  for (uint i = 0; i < Textures.size(); i++)
888  {
889  QString uniform = QString("s_texture%1").arg(i);
890  Program->setUniformValue(qPrintable(uniform), i);
892  if (Textures[i]->m_texture)
893  Textures[i]->m_texture->bind();
894  else
895  glBindTexture(textarget, Textures[i]->m_textureId);
896  }
897 
898  QOpenGLBuffer* buffer = first->m_vbo;
899  buffer->bind();
900  if (UpdateTextureVertices(first, Source, Destination, Rotation))
901  {
903  {
904  void* target = buffer->map(QOpenGLBuffer::WriteOnly);
905  if (target)
906  {
907  std::copy(first->m_vertexData.cbegin(),
908  first->m_vertexData.cend(),
909  static_cast<GLfloat*>(target));
910  }
911  buffer->unmap();
912  }
913  else
914  {
915  buffer->write(0, first->m_vertexData.data(), kVertexSize);
916  }
917  }
918 
919  glEnableVertexAttribArray(VERTEX_INDEX);
920  glEnableVertexAttribArray(TEXTURE_INDEX);
921  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
922  glVertexAttrib4f(COLOR_INDEX, 1.0, 1.0, 1.0, 1.0);
923  glVertexAttribPointerI(TEXTURE_INDEX, TEXTURE_SIZE, GL_FLOAT, GL_FALSE, TEXTURE_SIZE * sizeof(GLfloat), kTextureOffset);
924  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
925  glDisableVertexAttribArray(TEXTURE_INDEX);
926  glDisableVertexAttribArray(VERTEX_INDEX);
927  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
928  doneCurrent();
929 }
930 
931 static const float kLimitedRangeOffset = (16.0F / 255.0F);
932 static const float kLimitedRangeScale = (219.0F / 255.0F);
933 
935 void MythRenderOpenGL::ClearRect(QOpenGLFramebufferObject *Target, const QRect Area, int Color)
936 {
937  makeCurrent();
938  BindFramebuffer(Target);
939  glEnableVertexAttribArray(VERTEX_INDEX);
940 
941  // Set the fill color
942  float color = m_fullRange ? Color / 255.0F : (Color * kLimitedRangeScale) + kLimitedRangeOffset;
943  glVertexAttrib4f(COLOR_INDEX, color, color, color, 255.0F);
945 
946  GetCachedVBO(GL_TRIANGLE_STRIP, Area);
947  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
948  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
949 
950  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
951  glDisableVertexAttribArray(VERTEX_INDEX);
952  doneCurrent();
953 }
954 
955 void MythRenderOpenGL::DrawRect(QOpenGLFramebufferObject *Target,
956  const QRect Area, const QBrush &FillBrush,
957  const QPen &LinePen, int Alpha)
958 {
959  DrawRoundRect(Target, Area, 1, FillBrush, LinePen, Alpha);
960 }
961 
962 void MythRenderOpenGL::DrawRoundRect(QOpenGLFramebufferObject *Target,
963  const QRect Area, int CornerRadius,
964  const QBrush &FillBrush,
965  const QPen &LinePen, int Alpha)
966 {
967  makeCurrent();
968  BindFramebuffer(Target);
969 
970  int lineWidth = LinePen.width();
971  int halfline = lineWidth / 2;
972  int rad = CornerRadius - halfline;
973 
974  if ((Area.width() / 2) < rad)
975  rad = Area.width() / 2;
976 
977  if ((Area.height() / 2) < rad)
978  rad = Area.height() / 2;
979  int dia = rad * 2;
980 
981  QRect r(Area.left(), Area.top(), Area.width(), Area.height());
982 
983  QRect tl(r.left(), r.top(), rad, rad);
984  QRect tr(r.left() + r.width() - rad, r.top(), rad, rad);
985  QRect bl(r.left(), r.top() + r.height() - rad, rad, rad);
986  QRect br(r.left() + r.width() - rad, r.top() + r.height() - rad, rad, rad);
987 
988  glEnableVertexAttribArray(VERTEX_INDEX);
989 
990  if (FillBrush.style() != Qt::NoBrush)
991  {
992  // Get the shaders
993  QOpenGLShaderProgram* elip = m_defaultPrograms[kShaderCircle];
994  QOpenGLShaderProgram* fill = m_defaultPrograms[kShaderSimple];
995 
996  // Set the fill color
997  if (m_fullRange)
998  {
999  glVertexAttrib4f(COLOR_INDEX,
1000  FillBrush.color().red() / 255.0F,
1001  FillBrush.color().green() / 255.0F,
1002  FillBrush.color().blue() / 255.0F,
1003  (FillBrush.color().alpha() / 255.0F) * (Alpha / 255.0F));
1004  }
1005  else
1006  {
1007  glVertexAttrib4f(COLOR_INDEX,
1008  (FillBrush.color().red() * kLimitedRangeScale) + kLimitedRangeOffset,
1009  (FillBrush.color().blue() * kLimitedRangeScale) + kLimitedRangeOffset,
1010  (FillBrush.color().green() * kLimitedRangeScale) + kLimitedRangeOffset,
1011  (FillBrush.color().alpha() / 255.0F) * (Alpha / 255.0F));
1012  }
1013 
1014  // Set the radius
1015  m_parameters(2,0) = rad;
1016  m_parameters(3,0) = rad - 1.0F;
1017 
1018  // Enable the Circle shader
1019  SetShaderProjection(elip);
1020 
1021  // Draw the top left segment
1022  m_parameters(0,0) = tl.left() + rad;
1023  m_parameters(1,0) = tl.top() + rad;
1024 
1025  SetShaderProgramParams(elip, m_parameters, "u_parameters");
1026  GetCachedVBO(GL_TRIANGLE_STRIP, tl);
1027  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1028  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1029 
1030  // Draw the top right segment
1031  m_parameters(0,0) = tr.left();
1032  m_parameters(1,0) = tr.top() + rad;
1033  SetShaderProgramParams(elip, m_parameters, "u_parameters");
1034  GetCachedVBO(GL_TRIANGLE_STRIP, tr);
1035  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1036  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1037 
1038  // Draw the bottom left segment
1039  m_parameters(0,0) = bl.left() + rad;
1040  m_parameters(1,0) = bl.top();
1041  SetShaderProgramParams(elip, m_parameters, "u_parameters");
1042  GetCachedVBO(GL_TRIANGLE_STRIP, bl);
1043  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1044  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1045 
1046  // Draw the bottom right segment
1047  m_parameters(0,0) = br.left();
1048  m_parameters(1,0) = br.top();
1049  SetShaderProgramParams(elip, m_parameters, "u_parameters");
1050  GetCachedVBO(GL_TRIANGLE_STRIP, br);
1051  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1052  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1053 
1054  // Fill the remaining areas
1055  QRect main(r.left() + rad, r.top(), r.width() - dia, r.height());
1056  QRect left(r.left(), r.top() + rad, rad, r.height() - dia);
1057  QRect right(r.left() + r.width() - rad, r.top() + rad, rad, r.height() - dia);
1058 
1059  SetShaderProjection(fill);
1060 
1061  GetCachedVBO(GL_TRIANGLE_STRIP, main);
1062  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1063  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1064  GetCachedVBO(GL_TRIANGLE_STRIP, left);
1065  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1066  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1067  GetCachedVBO(GL_TRIANGLE_STRIP, right);
1068  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1069  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1070  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1071  }
1072 
1073  if (LinePen.style() != Qt::NoPen)
1074  {
1075  // Get the shaders
1076  QOpenGLShaderProgram* edge = m_defaultPrograms[kShaderCircleEdge];
1077  QOpenGLShaderProgram* vline = m_defaultPrograms[kShaderVertLine];
1078  QOpenGLShaderProgram* hline = m_defaultPrograms[kShaderHorizLine];
1079 
1080  // Set the line color
1081  if (m_fullRange)
1082  {
1083  glVertexAttrib4f(COLOR_INDEX,
1084  LinePen.color().red() / 255.0F,
1085  LinePen.color().green() / 255.0F,
1086  LinePen.color().blue() / 255.0F,
1087  (LinePen.color().alpha() / 255.0F) * (Alpha / 255.0F));
1088  }
1089  else
1090  {
1091  glVertexAttrib4f(COLOR_INDEX,
1092  (LinePen.color().red() * kLimitedRangeScale) + kLimitedRangeOffset,
1093  (LinePen.color().blue() * kLimitedRangeScale) + kLimitedRangeOffset,
1094  (LinePen.color().green() * kLimitedRangeScale) + kLimitedRangeOffset,
1095  (FillBrush.color().alpha() / 255.0F) * (Alpha / 255.0F));
1096  }
1097 
1098  // Set the radius and width
1099  m_parameters(2,0) = rad - lineWidth / 2.0F;
1100  m_parameters(3,0) = lineWidth / 2.0F;
1101 
1102  // Enable the edge shader
1103  SetShaderProjection(edge);
1104 
1105  // Draw the top left edge segment
1106  m_parameters(0,0) = tl.left() + rad;
1107  m_parameters(1,0) = tl.top() + rad;
1108  SetShaderProgramParams(edge, m_parameters, "u_parameters");
1109  GetCachedVBO(GL_TRIANGLE_STRIP, tl);
1110  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1111  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1112 
1113  // Draw the top right edge segment
1114  m_parameters(0,0) = tr.left();
1115  m_parameters(1,0) = tr.top() + rad;
1116  SetShaderProgramParams(edge, m_parameters, "u_parameters");
1117  GetCachedVBO(GL_TRIANGLE_STRIP, tr);
1118  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat),kVertexOffset);
1119  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1120 
1121  // Draw the bottom left edge segment
1122  m_parameters(0,0) = bl.left() + rad;
1123  m_parameters(1,0) = bl.top();
1124  SetShaderProgramParams(edge, m_parameters, "u_parameters");
1125  GetCachedVBO(GL_TRIANGLE_STRIP, bl);
1126  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1127  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1128 
1129  // Draw the bottom right edge segment
1130  m_parameters(0,0) = br.left();
1131  m_parameters(1,0) = br.top();
1132  SetShaderProgramParams(edge, m_parameters, "u_parameters");
1133  GetCachedVBO(GL_TRIANGLE_STRIP, br);
1134  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1135  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1136 
1137  // Vertical lines
1138  SetShaderProjection(vline);
1139 
1140  m_parameters(1,0) = lineWidth / 2.0F;
1141  QRect vl(r.left(), r.top() + rad, lineWidth, r.height() - dia);
1142 
1143  // Draw the left line segment
1144  m_parameters(0,0) = vl.left() + lineWidth;
1145  SetShaderProgramParams(vline, m_parameters, "u_parameters");
1146  GetCachedVBO(GL_TRIANGLE_STRIP, vl);
1147  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1148  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1149 
1150  // Draw the right line segment
1151  vl.translate(r.width() - lineWidth, 0);
1152  m_parameters(0,0) = vl.left();
1153  SetShaderProgramParams(vline, m_parameters, "u_parameters");
1154  GetCachedVBO(GL_TRIANGLE_STRIP, vl);
1155  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1156  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1157 
1158  // Horizontal lines
1159  SetShaderProjection(hline);
1160  QRect hl(r.left() + rad, r.top(), r.width() - dia, lineWidth);
1161 
1162  // Draw the top line segment
1163  m_parameters(0,0) = hl.top() + lineWidth;
1164  SetShaderProgramParams(hline, m_parameters, "u_parameters");
1165  GetCachedVBO(GL_TRIANGLE_STRIP, hl);
1166  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1167  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1168 
1169  // Draw the bottom line segment
1170  hl.translate(0, r.height() - lineWidth);
1171  m_parameters(0,0) = hl.top();
1172  SetShaderProgramParams(hline, m_parameters, "u_parameters");
1173  GetCachedVBO(GL_TRIANGLE_STRIP, hl);
1174  glVertexAttribPointerI(VERTEX_INDEX, VERTEX_SIZE, GL_FLOAT, GL_FALSE, VERTEX_SIZE * sizeof(GLfloat), kVertexOffset);
1175  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1176  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1177  }
1178  glDisableVertexAttribArray(VERTEX_INDEX);
1179  doneCurrent();
1180 }
1181 
1182 inline void MythRenderOpenGL::glVertexAttribPointerI(GLuint Index, GLint Size, GLenum Type, GLboolean Normalize,
1183  GLsizei Stride, const GLuint Value)
1184 {
1185 #pragma GCC diagnostic push
1186 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
1187  glVertexAttribPointer(Index, Size, Type, Normalize, Stride, reinterpret_cast<const char *>(Value));
1188 #pragma GCC diagnostic pop
1189 }
1190 
1192 {
1193  SetBlend(true);
1194  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1195  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1196  glDisable(GL_DEPTH_TEST);
1197  glDepthMask(GL_FALSE);
1198  glDisable(GL_CULL_FACE);
1199  glClearColor(0.0F, 0.0F, 0.0F, 0.0F);
1200  glClear(GL_COLOR_BUFFER_BIT);
1201  QOpenGLFramebufferObject::bindDefault();
1202  m_activeFramebuffer = defaultFramebufferObject();
1203  Flush();
1204 }
1205 
1206 QFunctionPointer MythRenderOpenGL::GetProcAddress(const QString &Proc) const
1207 {
1208  static const std::array<const QString,4> kExts { "", "ARB", "EXT", "OES" };
1209  QFunctionPointer result = nullptr;
1210  for (const auto & ext : kExts)
1211  {
1212  result = getProcAddress((Proc + ext).toLocal8Bit().constData());
1213  if (result)
1214  break;
1215  }
1216  if (result == nullptr)
1217  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Extension not found: %1").arg(Proc));
1218  return result;
1219 }
1220 
1221 QOpenGLBuffer* MythRenderOpenGL::CreateVBO(int Size, bool Release /*=true*/)
1222 {
1223  OpenGLLocker locker(this);
1224  auto* buffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
1225  if (buffer->create())
1226  {
1227  buffer->setUsagePattern(QOpenGLBuffer::StreamDraw);
1228  buffer->bind();
1229  buffer->allocate(Size);
1230  if (Release)
1231  QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1232  return buffer;
1233  }
1234  delete buffer;
1235  return nullptr;
1236 }
1237 
1239 {
1240  OpenGLLocker locker(this);
1241  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
1242  logDebugMarker("RENDER_RELEASE_START");
1244  ExpireVertices();
1245  ExpireVBOS();
1246  if (m_vao)
1247  {
1248  extraFunctions()->glDeleteVertexArrays(1, &m_vao);
1249  m_vao = 0;
1250  }
1251 
1252  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
1253  logDebugMarker("RENDER_RELEASE_END");
1254  delete m_openglDebugger;
1255  m_openglDebugger = nullptr;
1256  Flush();
1257 
1258  if (!m_cachedVertices.empty())
1259  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired vertices").arg(m_cachedVertices.size()));
1260 
1261  if (!m_cachedVBOS.empty())
1262  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired VBOs").arg(m_cachedVertices.size()));
1263 }
1264 
1266 {
1267  QStringList result;
1268  result.append(tr("QPA platform") + "\t: " + QGuiApplication::platformName());
1269  result.append(tr("OpenGL vendor") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
1270  result.append(tr("OpenGL renderer") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
1271  result.append(tr("OpenGL version") + "\t: " + reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1272  QSurfaceFormat fmt = format();
1273  result.append(tr("Color depth (RGBA)") + "\t: " + QString("%1%2%3%4")
1274  .arg(fmt.redBufferSize()).arg(fmt.greenBufferSize()).arg(fmt.blueBufferSize()).arg(fmt.alphaBufferSize()));
1275  return result;
1276 }
1277 
1279  const QRect Destination, int Rotation, qreal Scale)
1280 {
1281  if (!Texture || Texture->m_size.isEmpty())
1282  return false;
1283 
1284  if ((Texture->m_source == Source) && (Texture->m_destination == Destination) &&
1285  (Texture->m_rotation == Rotation))
1286  return false;
1287 
1288  Texture->m_source = Source;
1289  Texture->m_destination = Destination;
1290  Texture->m_rotation = Rotation;
1291 
1292  GLfloat *data = Texture->m_vertexData.data();
1293  QSize size = Texture->m_size;
1294 
1295  int width = Texture->m_crop ? min(Source.width(), size.width()) : Source.width();
1296  int height = Texture->m_crop ? min(Source.height(), size.height()) : Source.height();
1297 
1298  if (Texture->m_target != QOpenGLTexture::TargetRectangle)
1299  {
1300  data[0 + TEX_OFFSET] = Source.left() / static_cast<GLfloat>(size.width());
1301  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = (Source.top() + height) / static_cast<GLfloat>(size.height());
1302  data[6 + TEX_OFFSET] = (Source.left() + width) / static_cast<GLfloat>(size.width());
1303  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = Source.top() / static_cast<GLfloat>(size.height());
1304  }
1305  else
1306  {
1307  data[0 + TEX_OFFSET] = Source.left();
1308  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = (Source.top() + height);
1309  data[6 + TEX_OFFSET] = (Source.left() + width);
1310  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = Source.top();
1311  }
1312 
1313  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1314  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1315  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1316  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1317 
1318  width = Texture->m_crop ? min(static_cast<int>(width * Scale), Destination.width()) : Destination.width();
1319  height = Texture->m_crop ? min(static_cast<int>(height * Scale), Destination.height()) : Destination.height();
1320 
1321  data[2] = data[0] = Destination.left();
1322  data[5] = data[1] = Destination.top();
1323  data[4] = data[6] = Destination.left() + width;
1324  data[3] = data[7] = Destination.top() + height;
1325 
1326  if (Texture->m_rotation != 0)
1327  {
1328  if (Texture->m_rotation == 90)
1329  {
1330  GLfloat temp = data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET];
1331  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET];
1332  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = temp;
1333  data[2 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1334  data[4 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1335  }
1336  else if (Texture->m_rotation == -90)
1337  {
1338  GLfloat temp = data[0 + TEX_OFFSET];
1339  data[0 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1340  data[6 + TEX_OFFSET] = temp;
1341  data[3 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1342  data[5 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1343  }
1344  else if (abs(Texture->m_rotation) == 180)
1345  {
1346  GLfloat temp = data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET];
1347  data[(Texture->m_flip ? 7 : 1) + TEX_OFFSET] = data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET];
1348  data[(Texture->m_flip ? 1 : 7) + TEX_OFFSET] = temp;
1349  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1350  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1351  temp = data[0 + TEX_OFFSET];
1352  data[0 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1353  data[6 + TEX_OFFSET] = temp;
1354  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1355  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1356  }
1357  }
1358 
1359  return true;
1360 }
1361 
1362 GLfloat* MythRenderOpenGL::GetCachedVertices(GLuint Type, const QRect Area)
1363 {
1364  uint64_t ref = (static_cast<uint64_t>(Area.left()) & 0xfff) +
1365  ((static_cast<uint64_t>(Area.top()) & 0xfff) << 12) +
1366  ((static_cast<uint64_t>(Area.width()) & 0xfff) << 24) +
1367  ((static_cast<uint64_t>(Area.height()) & 0xfff) << 36) +
1368  ((static_cast<uint64_t>(Type & 0xfff)) << 48);
1369 
1370  if (m_cachedVertices.contains(ref))
1371  {
1372  m_vertexExpiry.removeOne(ref);
1373  m_vertexExpiry.append(ref);
1374  return m_cachedVertices[ref];
1375  }
1376 
1377  auto *vertices = new GLfloat[8];
1378 
1379  vertices[2] = vertices[0] = Area.left();
1380  vertices[5] = vertices[1] = Area.top();
1381  vertices[4] = vertices[6] = Area.left() + Area.width();
1382  vertices[3] = vertices[7] = Area.top() + Area.height();
1383 
1384  if (Type == GL_LINE_LOOP)
1385  {
1386  vertices[7] = vertices[1];
1387  vertices[5] = vertices[3];
1388  }
1389 
1390  m_cachedVertices.insert(ref, vertices);
1391  m_vertexExpiry.append(ref);
1393 
1394  return vertices;
1395 }
1396 
1398 {
1399  while (m_vertexExpiry.size() > Max)
1400  {
1401  uint64_t ref = m_vertexExpiry.first();
1402  m_vertexExpiry.removeFirst();
1403  GLfloat *vertices = nullptr;
1404  if (m_cachedVertices.contains(ref))
1405  vertices = m_cachedVertices.value(ref);
1406  m_cachedVertices.remove(ref);
1407  delete [] vertices;
1408  }
1409 }
1410 
1411 void MythRenderOpenGL::GetCachedVBO(GLuint Type, const QRect Area)
1412 {
1413  uint64_t ref = (static_cast<uint64_t>(Area.left()) & 0xfff) +
1414  ((static_cast<uint64_t>(Area.top()) & 0xfff) << 12) +
1415  ((static_cast<uint64_t>(Area.width()) & 0xfff) << 24) +
1416  ((static_cast<uint64_t>(Area.height()) & 0xfff) << 36) +
1417  ((static_cast<uint64_t>(Type & 0xfff)) << 48);
1418 
1419  if (m_cachedVBOS.contains(ref))
1420  {
1421  m_vboExpiry.removeOne(ref);
1422  m_vboExpiry.append(ref);
1423  m_cachedVBOS.value(ref)->bind();
1424  return;
1425  }
1426 
1427  GLfloat *vertices = GetCachedVertices(Type, Area);
1428  QOpenGLBuffer *vbo = CreateVBO(kTextureOffset, false);
1429  m_cachedVBOS.insert(ref, vbo);
1430  m_vboExpiry.append(ref);
1431 
1433  {
1434  void* target = vbo->map(QOpenGLBuffer::WriteOnly);
1435  if (target)
1436  memcpy(target, vertices, kTextureOffset);
1437  vbo->unmap();
1438  }
1439  else
1440  {
1441  vbo->write(0, vertices, kTextureOffset);
1442  }
1444 }
1445 
1447 {
1448  while (m_vboExpiry.size() > Max)
1449  {
1450  uint64_t ref = m_vboExpiry.first();
1451  m_vboExpiry.removeFirst();
1452  if (m_cachedVBOS.contains(ref))
1453  {
1454  QOpenGLBuffer *vbo = m_cachedVBOS.value(ref);
1455  delete vbo;
1456  m_cachedVBOS.remove(ref);
1457  }
1458  }
1459 }
1460 
1461 int MythRenderOpenGL::GetBufferSize(QSize Size, QOpenGLTexture::PixelFormat Format, QOpenGLTexture::PixelType Type)
1462 {
1463  int bytes = 0;
1464  int bpp = 0;;
1465 
1466  switch (Format)
1467  {
1468  case QOpenGLTexture::RGBA_Integer:
1469  case QOpenGLTexture::BGRA_Integer:
1470  case QOpenGLTexture::BGRA:
1471  case QOpenGLTexture::RGBA: bpp = 4; break;
1472  case QOpenGLTexture::RGB_Integer:
1473  case QOpenGLTexture::BGR_Integer:
1474  case QOpenGLTexture::BGR:
1475  case QOpenGLTexture::RGB: bpp = 3; break;
1476  case QOpenGLTexture::RG_Integer:
1477  case QOpenGLTexture::RG: bpp = 2; break;
1478  case QOpenGLTexture::Red:
1479  case QOpenGLTexture::Red_Integer:
1480  case QOpenGLTexture::Alpha:
1481  case QOpenGLTexture::Luminance: bpp = 1; break;
1482  default: break; // unsupported
1483  }
1484 
1485  switch (Type)
1486  {
1487  case QOpenGLTexture::Int8: bytes = sizeof(GLbyte); break;
1488  case QOpenGLTexture::UInt8: bytes = sizeof(GLubyte); break;
1489  case QOpenGLTexture::Int16: bytes = sizeof(GLshort); break;
1490  case QOpenGLTexture::UInt16: bytes = sizeof(GLushort); break;
1491  case QOpenGLTexture::Int32: bytes = sizeof(GLint); break;
1492  case QOpenGLTexture::UInt32: bytes = sizeof(GLuint); break;
1493  case QOpenGLTexture::Float32: bytes = sizeof(GLfloat); break;
1494  case QOpenGLTexture::UInt32_RGB10A2: bytes = sizeof(GLuint); break;
1495  default: break; // unsupported
1496  }
1497 
1498  if (!bpp || !bytes || Size.isEmpty())
1499  return 0;
1500 
1501  return Size.width() * Size.height() * bpp * bytes;
1502 }
1503 
1504 void MythRenderOpenGL::PushTransformation(const UIEffects &Fx, QPointF &Center)
1505 {
1506  QMatrix4x4 newtop = m_transforms.top();
1507  if (Fx.m_hzoom != 1.0F || Fx.m_vzoom != 1.0F || Fx.m_angle != 0.0F)
1508  {
1509  newtop.translate(static_cast<GLfloat>(Center.x()), static_cast<GLfloat>(Center.y()));
1510  newtop.scale(Fx.m_hzoom, Fx.m_vzoom);
1511  newtop.rotate(Fx.m_angle, 0, 0, 1);
1512  newtop.translate(static_cast<GLfloat>(-Center.x()), static_cast<GLfloat>(-Center.y()));
1513  }
1514  m_transforms.push(newtop);
1515 }
1516 
1518 {
1519  m_transforms.pop();
1520 }
1521 
1522 inline QOpenGLShaderProgram* ShaderError(QOpenGLShaderProgram *Shader, const QString &Source)
1523 {
1524  QString type = Source.isEmpty() ? "Shader link" : "Shader compile";
1525  LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1 error").arg(type));
1526  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Log:"));
1527  LOG(VB_GENERAL, LOG_ERR, "\n" + Shader->log());
1528  if (!Source.isEmpty())
1529  {
1530  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Source:"));
1531  LOG(VB_GENERAL, LOG_ERR, "\n" + Source);
1532  }
1533  delete Shader;
1534  return nullptr;
1535 }
1536 
1537 QOpenGLShaderProgram *MythRenderOpenGL::CreateShaderProgram(const QString &Vertex, const QString &Fragment)
1538 {
1539  if (!(m_features & Shaders))
1540  return nullptr;
1541 
1542  OpenGLLocker locker(this);
1543  QString vertex = Vertex.isEmpty() ? kDefaultVertexShader : Vertex;
1544  QString fragment = Fragment.isEmpty() ? kDefaultFragmentShader: Fragment;
1545  auto *program = new QOpenGLShaderProgram();
1546  if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex))
1547  return ShaderError(program, vertex);
1548  if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment))
1549  return ShaderError(program, fragment);
1550  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
1551  {
1552  QList<QOpenGLShader*> shaders = program->shaders();
1553  for (QOpenGLShader* shader : qAsConst(shaders))
1554  LOG(VB_GENERAL, LOG_DEBUG, "\n" + shader->sourceCode());
1555  }
1556  program->bindAttributeLocation("a_position", VERTEX_INDEX);
1557  program->bindAttributeLocation("a_color", COLOR_INDEX);
1558  program->bindAttributeLocation("a_texcoord0", TEXTURE_INDEX);
1559  if (!program->link())
1560  return ShaderError(program, "");
1561  return program;
1562 }
1563 
1564 QOpenGLShaderProgram* MythRenderOpenGL::CreateComputeShader(const QString &Source)
1565 {
1566  if (!(m_extraFeaturesUsed & kGLComputeShaders) || Source.isEmpty())
1567  return nullptr;
1568 
1569  OpenGLLocker locker(this);
1570  auto *program = new QOpenGLShaderProgram();
1571  if (!program->addShaderFromSourceCode(QOpenGLShader::Compute, Source))
1572  return ShaderError(program, Source);
1573 
1574  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
1575  {
1576  QList<QOpenGLShader*> shaders = program->shaders();
1577  for (QOpenGLShader* shader : qAsConst(shaders))
1578  LOG(VB_GENERAL, LOG_DEBUG, "\n" + shader->sourceCode());
1579  }
1580 
1581  if (!program->link())
1582  return ShaderError(program, "");
1583  return program;
1584 }
1585 
1586 void MythRenderOpenGL::DeleteShaderProgram(QOpenGLShaderProgram *Program)
1587 {
1588  makeCurrent();
1589  delete Program;
1590  m_cachedMatrixUniforms.clear();
1591  m_activeProgram = nullptr;
1592  m_cachedUniformLocations.remove(Program);
1593  doneCurrent();
1594 }
1595 
1596 bool MythRenderOpenGL::EnableShaderProgram(QOpenGLShaderProgram* Program)
1597 {
1598  if (!Program)
1599  return false;
1600 
1601  if (m_activeProgram == Program)
1602  return true;
1603 
1604  makeCurrent();
1605  Program->bind();
1606  m_activeProgram = Program;
1607  doneCurrent();
1608  return true;
1609 }
1610 
1611 void MythRenderOpenGL::SetShaderProjection(QOpenGLShaderProgram *Program)
1612 {
1613  if (Program)
1614  {
1615  SetShaderProgramParams(Program, m_projection, "u_projection");
1616  SetShaderProgramParams(Program, m_transforms.top(), "u_transform");
1617  }
1618 }
1619 
1620 void MythRenderOpenGL::SetShaderProgramParams(QOpenGLShaderProgram *Program, const QMatrix4x4 &Value, const char *Uniform)
1621 {
1622  OpenGLLocker locker(this);
1623  if (!Uniform || !EnableShaderProgram(Program))
1624  return;
1625 
1626  // Uniform value cacheing
1627  QString tag = QString("%1-%2").arg(Program->programId()).arg(Uniform);
1628  QHash<QString,QMatrix4x4>::iterator it = m_cachedMatrixUniforms.find(tag);
1629  if (it == m_cachedMatrixUniforms.end())
1630  m_cachedMatrixUniforms.insert(tag, Value);
1631  else if (!qFuzzyCompare(Value, it.value()))
1632  it.value() = Value;
1633  else
1634  return;
1635 
1636  // Uniform location cacheing
1637  QByteArray uniform(Uniform);
1638  GLint location = 0;
1639  QHash<QByteArray, GLint> &uniforms = m_cachedUniformLocations[Program];
1640  if (uniforms.contains(uniform))
1641  {
1642  location = uniforms[uniform];
1643  }
1644  else
1645  {
1646  location = Program->uniformLocation(Uniform);
1647  uniforms.insert(uniform, location);
1648  }
1649 
1650  Program->setUniformValue(location, Value);
1651 }
1652 
1654 {
1664 }
1665 
1667 {
1668  for (auto & program : m_defaultPrograms)
1669  {
1670  DeleteShaderProgram(program);
1671  program = nullptr;
1672  }
1673 }
1674 
1676 {
1677  m_projection.setToIdentity();
1678  m_projection.ortho(m_viewport);
1679 }
1680 
1681 bool MythRenderOpenGL::GetGPUMemory(int &Available, int &Total)
1682 {
1683  OpenGLLocker locker(this);
1685  {
1686  GLint kb = 0;
1687  glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &kb);
1688  Total = kb / 1024;
1690  Available = kb / 1024;
1691  return true;
1692  }
1693  return false;
1694 }
1695 
1707 {
1708  OpenGLLocker locker(this);
1709  QSize size{256, 256};
1710  QOpenGLFramebufferObject *fbo = CreateFramebuffer(size, true);
1711  if (fbo)
1712  {
1714  delete fbo;
1715  }
1716 }
MythRenderOpenGL::Init
bool Init(void)
Definition: mythrenderopengl.cpp:210
Source
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:143
MythGLTexture::m_source
QRect m_source
Definition: mythrenderopengl.h:74
MYTH_GLMAPBUFFERPROC
GLvoid *(APIENTRY *)(GLenum target, GLenum access) MYTH_GLMAPBUFFERPROC
Definition: mythrenderopengldefs.h:33
bbciplayer.main
main
Definition: bbciplayer.py:263
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:38
MythGLTexture
Definition: mythrenderopengl.h:57
kTextureOffset
static const GLuint kTextureOffset
Definition: mythrenderopengl.cpp:38
mythrenderopenglshaders.h
kGLNVMemory
@ kGLNVMemory
Definition: mythrenderopengl.h:48
kCircleEdgeFragmentShader
static const QString kCircleEdgeFragmentShader
Definition: mythrenderopenglshaders.h:80
kGLExtRGBA16
@ kGLExtRGBA16
Definition: mythrenderopengl.h:44
copy
long long copy(QFile &dst, QFile &src, uint block_size)
Copies src file to dst file.
Definition: mythmiscutil.cpp:309
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:512
MythGLTexture::m_texture
QOpenGLTexture * m_texture
Definition: mythrenderopengl.h:66
MythRenderOpenGL::GetMaxTextureSize
int GetMaxTextureSize(void) const
Definition: mythrenderopengl.cpp:451
MythGLTexture::m_vertexData
std::array< GLfloat, 16 > m_vertexData
Definition: mythrenderopengl.h:76
kShaderCircle
@ kShaderCircle
Definition: mythrenderopengl.h:88
MythRenderOpenGL::DeleteFramebuffer
void DeleteFramebuffer(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:772
MythRenderOpenGL::~MythRenderOpenGL
~MythRenderOpenGL() override
Definition: mythrenderopengl.cpp:136
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:802
MythRenderOpenGL::CreateComputeShader
QOpenGLShaderProgram * CreateComputeShader(const QString &Source)
Definition: mythrenderopengl.cpp:1564
MythRenderOpenGL::ExpireVertices
void ExpireVertices(int Max=0)
Definition: mythrenderopengl.cpp:1397
kSimpleFragmentShader
static const QString kSimpleFragmentShader
Definition: mythrenderopenglshaders.h:49
MythRenderOpenGL::m_cachedVBOS
QMap< uint64_t, QOpenGLBuffer * > m_cachedVBOS
Definition: mythrenderopengl.h:215
MythRenderOpenGL::m_fullRange
bool m_fullRange
Definition: mythrenderopengl.h:234
MythEGL::GetEGLDisplay
void * GetEGLDisplay(void)
Definition: mythegl.cpp:80
MythRenderOpenGL::m_maxTextureUnits
int m_maxTextureUnits
Definition: mythrenderopengl.h:227
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:1206
MythGLTexture::m_data
unsigned char * m_data
Definition: mythrenderopengl.h:63
MythRenderOpenGL::logDebugMarker
void logDebugMarker(const QString &Message)
Definition: mythrenderopengl.cpp:193
MythRenderOpenGL::m_blend
bool m_blend
Definition: mythrenderopengl.h:232
OpenGLLocker::~OpenGLLocker
~OpenGLLocker()
Definition: mythrenderopengl.cpp:60
arg
arg(title).arg(filename).arg(doDelete))
MythRenderOpenGL::ClearRect
void ClearRect(QOpenGLFramebufferObject *Target, QRect Area, int Color)
An optimised method to clear a QRect to the given color.
Definition: mythrenderopengl.cpp:935
kShaderVertLine
@ kShaderVertLine
Definition: mythrenderopengl.h:90
MythRenderOpenGL::PushTransformation
void PushTransformation(const UIEffects &Fx, QPointF &Center)
Definition: mythrenderopengl.cpp:1504
kRenderOpenGL
@ kRenderOpenGL
Definition: mythrender_base.h:19
MythRenderOpenGL::m_parameters
QMatrix4x4 m_parameters
Definition: mythrenderopengl.h:237
MythRenderOpenGL::DrawBitmap
void DrawBitmap(MythGLTexture *Texture, QOpenGLFramebufferObject *Target, QRect Source, QRect Destination, QOpenGLShaderProgram *Program, int Alpha=255, qreal Scale=1.0)
Definition: mythrenderopengl.cpp:809
MythDate::Format
Format
Definition: mythdate.h:13
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:29
kGLLegacyTextures
@ kGLLegacyTextures
Definition: mythrenderopengl.h:47
MythRenderOpenGL::ExpireVBOS
void ExpireVBOS(int Max=0)
Definition: mythrenderopengl.cpp:1446
MythRenderOpenGL::m_vertexExpiry
QList< uint64_t > m_vertexExpiry
Definition: mythrenderopengl.h:214
kShaderHorizLine
@ kShaderHorizLine
Definition: mythrenderopengl.h:91
kLimitedRangeOffset
static const float kLimitedRangeOffset
Definition: mythrenderopengl.cpp:931
MythMainWindow::GetRenderDevice
MythRender * GetRenderDevice()
Definition: mythmainwindow.cpp:298
Image
Definition: image.h:31
HasMythMainWindow
bool HasMythMainWindow(void)
Definition: mythmainwindow.cpp:113
kGLExtRects
@ kGLExtRects
Definition: mythrenderopengl.h:43
kGLExtSubimage
@ kGLExtSubimage
Definition: mythrenderopengl.h:45
MythRenderOpenGL::CreateFramebufferTexture
MythGLTexture * CreateFramebufferTexture(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:760
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:233
kDrawVertexShader
static const QString kDrawVertexShader
Definition: mythrenderopenglshaders.h:56
MythRenderOpenGL::GetFeatures
QOpenGLFunctions::OpenGLFeatures GetFeatures(void) const
Definition: mythrenderopengl.cpp:466
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
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:1620
MythRenderOpenGL::m_ready
bool m_ready
Definition: mythrenderopengl.h:200
OpenGLLocker::m_render
MythRenderOpenGL * m_render
Definition: mythrenderopengl.h:260
MAX_VERTEX_CACHE
#define MAX_VERTEX_CACHE
Definition: mythrenderopengl.cpp:41
MythMainWindow::getMainWindow
static MythMainWindow * getMainWindow(bool useDB=true)
Return the existing main window, or create one.
Definition: mythmainwindow.cpp:84
MythRenderOpenGL::m_transforms
QStack< QMatrix4x4 > m_transforms
Definition: mythrenderopengl.h:236
MythRenderOpenGL::m_activeProgram
QOpenGLShaderProgram * m_activeProgram
Definition: mythrenderopengl.h:210
MythRenderOpenGL::m_flushEnabled
bool m_flushEnabled
Definition: mythrenderopengl.h:244
mythrenderopengl.h
MythRenderOpenGL::m_cachedUniformLocations
QHash< QOpenGLShaderProgram *, QHash< QByteArray, GLint > > m_cachedUniformLocations
Definition: mythrenderopengl.h:239
kDefaultVertexShader
static const QString kDefaultVertexShader
Definition: mythrenderopenglshaders.h:6
MythRenderOpenGL::Check16BitFBO
void Check16BitFBO(void)
Check for 16bit framebufferobject support.
Definition: mythrenderopengl.cpp:1706
MythRenderOpenGL::m_extraFeaturesUsed
int m_extraFeaturesUsed
Definition: mythrenderopengl.h:225
mythlogging.h
kGL16BitFBO
@ kGL16BitFBO
Definition: mythrenderopengl.h:49
Source
Definition: channelsettings.cpp:69
MythRenderOpenGL::kVertexSize
static const GLuint kVertexSize
Definition: mythrenderopengl.h:130
MythGLTexture::m_vbo
QOpenGLBuffer * m_vbo
Definition: mythrenderopengl.h:69
MythRenderOpenGL::CreateTextureFromQImage
MythGLTexture * CreateTextureFromQImage(QImage *Image)
Definition: mythrenderopengl.cpp:628
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:955
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:1182
GLYesNo
#define GLYesNo(arg)
Definition: mythrenderopengl.cpp:397
kHorizLineFragmentShader
static const QString kHorizLineFragmentShader
Definition: mythrenderopenglshaders.h:105
debug
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
MythRenderOpenGL::PopTransformation
void PopTransformation(void)
Definition: mythrenderopengl.cpp:1517
ShaderError
QOpenGLShaderProgram * ShaderError(QOpenGLShaderProgram *Shader, const QString &Source)
Definition: mythrenderopengl.cpp:1522
MythRenderOpenGL::swapBuffers
void swapBuffers()
Definition: mythrenderopengl.cpp:517
kGLGeometryShaders
@ kGLGeometryShaders
Definition: mythrenderopengl.h:51
MythRenderOpenGL::makeCurrent
void makeCurrent()
Definition: mythrenderopengl.cpp:564
MythRenderOpenGL::DeleteTexture
void DeleteTexture(MythGLTexture *Texture)
Definition: mythrenderopengl.cpp:714
MythRenderOpenGL::GetDescription
QStringList GetDescription(void) override
Definition: mythrenderopengl.cpp:1265
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:962
MythRenderOpenGL::GetExtraFeatures
int GetExtraFeatures(void) const
Definition: mythrenderopengl.cpp:461
MythRenderOpenGL::DeleteShaderProgram
void DeleteShaderProgram(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1586
TEX_OFFSET
#define TEX_OFFSET
Definition: mythrenderopengl.h:54
MythRenderOpenGL::MessageLogged
void MessageLogged(const QOpenGLDebugMessage &Message)
Definition: mythrenderopengl.cpp:146
MythRenderOpenGL::CreateVBO
QOpenGLBuffer * CreateVBO(int Size, bool Release=true)
Definition: mythrenderopengl.cpp:1221
uint
unsigned int uint
Definition: compat.h:141
MythRenderOpenGL::CreateDefaultShaders
bool CreateDefaultShaders(void)
Definition: mythrenderopengl.cpp:1653
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
kGLBufferMap
@ kGLBufferMap
Definition: mythrenderopengl.h:42
kSimpleVertexShader
static const QString kSimpleVertexShader
Definition: mythrenderopenglshaders.h:38
kLimitedRangeScale
static const float kLimitedRangeScale
Definition: mythrenderopengl.cpp:932
MythGLTexture::m_bufferSize
int m_bufferSize
Definition: mythrenderopengl.h:64
kGLFeatNone
@ kGLFeatNone
Definition: mythrenderopengl.h:41
MythRenderOpenGL::SetBlend
void SetBlend(bool Enable)
Definition: mythrenderopengl.cpp:605
OpenGLLocker::OpenGLLocker
OpenGLLocker(MythRenderOpenGL *Render)
Definition: mythrenderopengl.cpp:53
kShaderSimple
@ kShaderSimple
Definition: mythrenderopengl.h:86
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:251
mythxdisplay.h
MythGLTexture::m_target
GLenum m_target
Definition: mythrenderopengl.h:77
kCircleFragmentShader
static const QString kCircleFragmentShader
Definition: mythrenderopenglshaders.h:69
MythRenderOpenGL::doneCurrent
void doneCurrent()
Definition: mythrenderopengl.cpp:572
MythRenderOpenGL::GetMaxTextureUnits
int GetMaxTextureUnits(void) const
Definition: mythrenderopengl.cpp:456
GL_TEXTURE0
#define GL_TEXTURE0
Definition: mythrenderopengldefs.h:9
MythRenderOpenGL
Definition: mythrenderopengl.h:99
MythEGL
Definition: mythegl.h:18
UIEffects::m_vzoom
float m_vzoom
Definition: mythuianimation.h:37
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:231
MythRenderOpenGL::m_projection
QMatrix4x4 m_projection
Definition: mythrenderopengl.h:235
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
MythRenderOpenGL::BindFramebuffer
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
Definition: mythrenderopengl.cpp:782
MythGLTexture::m_textureId
GLuint m_textureId
Definition: mythrenderopengl.h:65
mythcorecontext.h
MythRenderOpenGL::m_cachedMatrixUniforms
QHash< QString, QMatrix4x4 > m_cachedMatrixUniforms
Definition: mythrenderopengl.h:238
MythRender
Definition: mythrender_base.h:24
COLOR_INDEX
#define COLOR_INDEX
Definition: mythrenderopengl.cpp:32
MythRenderOpenGL::m_extraFeatures
int m_extraFeatures
Definition: mythrenderopengl.h:224
MythRenderOpenGL::SetMatrixView
void SetMatrixView(void)
Definition: mythrenderopengl.cpp:1675
GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
#define GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
Definition: mythrenderopengldefs.h:25
MythRenderOpenGL::m_openGLDebuggerFilter
QOpenGLDebugMessage::Types m_openGLDebuggerFilter
Definition: mythrenderopengl.h:250
kVertLineFragmentShader
static const QString kVertLineFragmentShader
Definition: mythrenderopenglshaders.h:93
MythRenderOpenGL::GetCachedVBO
void GetCachedVBO(GLuint Type, QRect Area)
Definition: mythrenderopengl.cpp:1411
TEXTURE_INDEX
#define TEXTURE_INDEX
Definition: mythrenderopengl.cpp:33
MythGLTexture::m_size
QSize m_size
Definition: mythrenderopengl.h:70
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:240
MythRenderOpenGL::SetTextureFilters
void SetTextureFilters(MythGLTexture *Texture, QOpenGLTexture::Filter Filter, QOpenGLTexture::WrapMode Wrap=QOpenGLTexture::ClampToEdge)
Definition: mythrenderopengl.cpp:677
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:66
MythXDisplay::DisplayIsRemote
static bool DisplayIsRemote(void)
Determine if we are running a remote X11 session.
Definition: mythxdisplay.cpp:62
kDefaultFragmentShader
static const QString kDefaultFragmentShader
Definition: mythrenderopenglshaders.h:20
MythRenderOpenGL::DeleteDefaultShaders
void DeleteDefaultShaders(void)
Definition: mythrenderopengl.cpp:1666
UIEffects
Definition: mythuianimation.h:10
MythRenderOpenGL::MythRenderOpenGL
MythRenderOpenGL(const QSurfaceFormat &Format, QWidget *Widget)
Definition: mythrenderopengl.cpp:123
kGLComputeShaders
@ kGLComputeShaders
Definition: mythrenderopengl.h:50
MythRenderOpenGL::Init2DState
void Init2DState(void)
Definition: mythrenderopengl.cpp:1191
MythRenderOpenGL::m_lock
QMutex m_lock
Definition: mythrenderopengl.h:219
MythRenderOpenGL::UpdateTextureVertices
static bool UpdateTextureVertices(MythGLTexture *Texture, QRect Source, QRect Destination, int Rotation, qreal Scale=1.0)
Definition: mythrenderopengl.cpp:1278
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:1238
MythRenderOpenGL::GetCachedVertices
GLfloat * GetCachedVertices(GLuint Type, QRect Area)
Definition: mythrenderopengl.cpp:1362
UIEffects::m_hzoom
float m_hzoom
Definition: mythuianimation.h:36
MythRenderOpenGL::m_lockLevel
int m_lockLevel
Definition: mythrenderopengl.h:220
MythGLTexture::MythGLTexture
MythGLTexture(QOpenGLTexture *Texture)
Definition: mythrenderopengl.cpp:43
MYTH_GLUNMAPBUFFERPROC
GLboolean(APIENTRY *)(GLenum target) MYTH_GLUNMAPBUFFERPROC
Definition: mythrenderopengldefs.h:34
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:1461
MythRenderOpenGL::IsRecommendedRenderer
bool IsRecommendedRenderer(void)
Definition: mythrenderopengl.cpp:471
MythRenderOpenGL::m_viewport
QRect m_viewport
Definition: mythrenderopengl.h:230
mythmainwindow.h
MythRenderOpenGL::GetGPUMemory
bool GetGPUMemory(int &Available, int &Total)
Definition: mythrenderopengl.cpp:1681
kGLTiled
@ kGLTiled
Definition: mythrenderopengl.h:46
MythRenderOpenGL::contextToBeDestroyed
void contextToBeDestroyed(void)
Definition: mythrenderopengl.cpp:205
MythRenderOpenGL::m_openglDebugger
QOpenGLDebugLogger * m_openglDebugger
Definition: mythrenderopengl.h:249
MythRenderOpenGL::SetShaderProjection
void SetShaderProjection(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1611
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:35
Color
Definition: graphic.h:7
kShaderDefault
@ kShaderDefault
Definition: mythrenderopengl.h:87
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:1537
kShaderCircleEdge
@ kShaderCircleEdge
Definition: mythrenderopengl.h:89
VERTEX_INDEX
#define VERTEX_INDEX
Definition: mythrenderopengl.cpp:31
MythRenderOpenGL::EnableShaderProgram
bool EnableShaderProgram(QOpenGLShaderProgram *Program)
Definition: mythrenderopengl.cpp:1596
OpenGLLocker
Definition: mythrenderopengl.h:255