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