MythTV  master
mythrender_opengl.cpp
Go to the documentation of this file.
1 #include "mythrender_opengl.h"
2 
3 #include <algorithm>
4 using std::min;
5 
6 #include <QLibrary>
7 #include <QPainter>
8 #ifdef USE_OPENGL_QT5
9 #include <QWindow>
10 #include <QGLFormat>
11 #endif
12 #include <QWidget>
13 
14 #include "mythlogging.h"
15 #include "mythuitype.h"
16 #include "mythxdisplay.h"
17 
18 #define LOC QString("OpenGL: ")
19 
20 #include "mythrender_opengl2.h"
21 #ifdef USING_OPENGLES
22 #include "mythrender_opengl2es.h"
23 #else
24 #include "mythrender_opengl1.h"
25 #endif
26 
27 #ifdef CONFIG_XNVCTRL
28 #include "util-nvctrl.h"
29 #endif
30 
31 #ifdef Q_OS_ANDROID
32 #include <android/log.h>
33 #include <QWindow>
34 #endif
35 
36 static const GLuint kTextureOffset = 8 * sizeof(GLfloat);
37 
38 static inline int __glCheck__(const QString &loc, const char* fileName, int n)
39 {
40  int error = glGetError();
41  if (error)
42  {
43  LOG(VB_GENERAL, LOG_ERR, QString("%1: %2 @ %3, %4")
44  .arg(loc).arg(error).arg(fileName).arg(n));
45  }
46  return error;
47 }
48 
49 #define MAX_VERTEX_CACHE 500
50 #define glCheck() __glCheck__(LOC, __FILE__, __LINE__)
51 
52 OpenGLLocker::OpenGLLocker(MythRenderOpenGL *render) : m_render(render)
53 {
54  if (m_render)
56 }
57 
59 {
60  if (m_render)
62 }
63 
65  QPaintDevice* device)
66 {
67  QString display = getenv("DISPLAY");
68  // Determine if we are running a remote X11 session
69  // DISPLAY=:x or DISPLAY=unix:x are local
70  // DISPLAY=hostname:x is remote
71  // DISPLAY=/xxx/xxx/.../org.macosforge.xquartz:x is local OS X
72  // x can be numbers n or n.n
73  // Anything else including DISPLAY not set is assumed local,
74  // in that case we are probably not running under X11
75  if (!display.isEmpty()
76  && !display.startsWith(":")
77  && !display.startsWith("unix:")
78  && !display.startsWith("/")
79  && display.contains(':'))
80  {
81  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL is disabled for Remote X Session");
82  return nullptr;
83  }
84 #ifdef USE_OPENGL_QT5
85  MythRenderFormat format = QSurfaceFormat::defaultFormat();
86  format.setDepthBufferSize(0);
87  format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
88 # ifdef USING_OPENGLES
89  format.setRenderableType(QSurfaceFormat::OpenGLES);
90 # endif
91 #else
92  MythRenderFormat format = QGLFormat(QGL::NoDepthBuffer);
93 #endif
94 
95  bool setswapinterval = false;
96  int synctovblank = -1;
97 
98 #ifdef CONFIG_XNVCTRL
99  synctovblank = CheckNVOpenGLSyncToVBlank();
100 #endif
101 
102  if (synctovblank < 0)
103  {
104  LOG(VB_GENERAL, LOG_WARNING, LOC + "Could not determine whether Sync "
105  "to VBlank is enabled.");
106  }
107  else if (synctovblank == 0)
108  {
109  // currently only Linux NVidia is supported and there is no way of
110  // forcing sync to vblank after the app has started. util-nvctrl will
111  // warn the user and offer advice on settings.
112  }
113  else
114  {
115  LOG(VB_GENERAL, LOG_INFO, LOC + "Sync to VBlank is enabled (good!)");
116  }
117 
118 #if defined(Q_OS_MAC)
119  LOG(VB_GENERAL, LOG_INFO, LOC + "Forcing swap interval for OS X.");
120  setswapinterval = true;
121 #endif
122 
123  if (setswapinterval)
124  format.setSwapInterval(1);
125 
126 #if ANDROID
127  int openGLVersionFlags = QGLFormat::OpenGL_ES_Version_2_0;
128  LOG(VB_GENERAL, LOG_INFO, "OpenGL ES2 forced for Android");
129 #elif defined USE_OPENGL_QT5 && defined USING_OPENGLES
130  int openGLVersionFlags = QGLFormat::OpenGL_ES_Version_2_0;
131 #else
132  // Check OpenGL version supported
133  int openGLVersionFlags = QGLFormat::openGLVersionFlags();
134 #endif
135 
136 #ifdef USING_OPENGLES
137  Q_UNUSED(painter);
138  if (!(openGLVersionFlags & QGLFormat::OpenGL_ES_Version_2_0))
139  {
140  LOG(VB_GENERAL, LOG_WARNING,
141  "Using OpenGL ES 2.0 render, however OpenGL ES 2.0 "
142  "version not supported");
143  }
144  if (device)
145  return new MythRenderOpenGL2ES(format, device);
146  return new MythRenderOpenGL2ES(format);
147 #else
148  if (((openGLVersionFlags & QGLFormat::OpenGL_Version_2_0) != 0) &&
149  (painter.contains(OPENGL2_PAINTER) || painter.contains(AUTO_PAINTER) ||
150  painter.isEmpty()))
151  {
152  LOG(VB_GENERAL, LOG_INFO, "Trying the OpenGL 2.0 render");
153  format.setVersion(2,0);
154  if (device)
155  return new MythRenderOpenGL2(format, device);
156  return new MythRenderOpenGL2(format);
157  }
158 
159  if (!(openGLVersionFlags & QGLFormat::OpenGL_Version_1_2))
160  {
161  LOG(VB_GENERAL, LOG_WARNING, "OpenGL 1.2 not supported, get new hardware!");
162  return nullptr;
163  }
164 
165  LOG(VB_GENERAL, LOG_INFO, "Trying the OpenGL 1.2 render");
166  format.setVersion(1,3);
167  if (device)
168  return new MythRenderOpenGL1(format, device);
169  return new MythRenderOpenGL1(format);
170 
171 #endif
172 }
173 
174 #ifdef USE_OPENGL_QT5
175 MythRenderOpenGL::MythRenderOpenGL(const MythRenderFormat& format, QPaintDevice* device,
177  : MythRender(type), m_lock(QMutex::Recursive)
178 {
179  QWidget *w = dynamic_cast<QWidget*>(device);
180  m_window = (w) ? w->windowHandle() : nullptr;
183  setFormat(format);
184 }
185 
187  : MythRender(type), m_lock(QMutex::Recursive), m_window(nullptr)
188 {
191  setFormat(format);
192 }
193 #else
194 MythRenderOpenGL::MythRenderOpenGL(const MythRenderFormat& format, QPaintDevice* device,
196  : QGLContext(format, device), MythRender(type), m_lock(QMutex::Recursive)
197 {
200 }
201 
203  : QGLContext(format), MythRender(type), m_lock(QMutex::Recursive)
204 {
207 }
208 #endif
209 
211 {
212  if (!isValid())
213  {
214  LOG(VB_GENERAL, LOG_ERR, LOC + "Init an invalid context."
215  " Missing call to setWidget or create?");
216  return;
217  }
218 
219  OpenGLLocker locker(this);
220  InitProcs();
221  Init2DState();
222  InitFeatures();
223 
224  LOG(VB_GENERAL, LOG_INFO, LOC + "Initialised MythRenderOpenGL");
225 }
226 
228 {
229  bool recommended = true;
230  OpenGLLocker locker(this);
231  QString renderer = (const char*) glGetString(GL_RENDERER);
232 
233  if (!IsDirectRendering())
234  {
235  LOG(VB_GENERAL, LOG_WARNING, LOC +
236  "OpenGL is using software rendering.");
237  recommended = false;
238  }
239  else if (renderer.contains("Software Rasterizer", Qt::CaseInsensitive))
240  {
241  LOG(VB_GENERAL, LOG_WARNING, LOC +
242  "OpenGL is using software rasterizer.");
243  recommended = false;
244  }
245  else if (renderer.contains("softpipe", Qt::CaseInsensitive))
246  {
247  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL seems to be using software "
248  "fallback. Please check your OpenGL driver installation, "
249  "configuration, and device permissions.");
250  recommended = false;
251  }
252  return recommended;
253 }
254 
255 #ifdef USE_OPENGL_QT5
257 {
258  return QGLFormat::fromSurfaceFormat(format()).directRendering();
259 }
260 
261 void MythRenderOpenGL::swapBuffers()
262 {
263  QOpenGLContext::swapBuffers(m_window);
264 }
265 
266 void MythRenderOpenGL::setWidget(QWidget *w)
267 {
268  if (!w)
269  return;
270 
271  w->winId(); // Ensure native window
272  m_window = w->windowHandle();
273  if (!m_window)
274  {
275  w = w->nativeParentWidget();
276  if (w)
277  m_window = w->windowHandle();
278  }
279 
280 #ifdef ANDROID
281  // change all window surfacetypes to OpenGLSurface
282  // otherwise the raster gets painted on top of the GL surface
283  m_window->setSurfaceType(QWindow::OpenGLSurface);
284  QWidget* wNativeParent = w->nativeParentWidget();
285  if (wNativeParent)
286  wNativeParent->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
287 #endif
288 
289  if (!create())
290  LOG(VB_GENERAL, LOG_WARNING, LOC + "setWidget create failed");
291  else if (w)
292  w->setAttribute(Qt::WA_PaintOnScreen);
293 }
294 #else
296 {
297  return format().directRendering();
298 }
299 
300 void MythRenderOpenGL::setWidget(QGLWidget *w)
301 {
302  setDevice(w);
303 
304 #ifdef ANDROID
305  // change all window surfacetypes to OpenGLSurface
306  // otherwise the raster gets painted on top of the GL surface
307  m_window->setSurfaceType(QWindow::OpenGLSurface);
308  QWidget* wNativeParent = w->nativeParentWidget();
309  if (wNativeParent)
310  wNativeParent->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
311 #endif
312 
313  w->setContext(this);
314 }
315 #endif
316 
318 {
319  m_lock.lock();
320 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
321  // Testing MythRenderOpenGL::currentContext is not reliable
322  if (!m_lock_level++)
323  {
324 #ifdef USE_OPENGL_QT5
325  QOpenGLContext::makeCurrent(m_window);
326 #else
327  QGLContext::makeCurrent();
328 #endif
329  }
330 #else
331  if (this != MythRenderOpenGL::currentContext())
332  QGLContext::makeCurrent();
333  m_lock_level++;
334  #endif
335 }
336 
338 {
339  m_lock_level--;
340  // Calling doneCurrent is strictly not necessary and causes the next call
341  // to makeCurrent to take considerably longer
342 #if 0
343  if (m_lock_level == 0)
344  QGLContext::doneCurrent();
345 #endif
346  if (m_lock_level < 0)
347  LOG(VB_GENERAL, LOG_ERR, LOC + "Mis-matched calls to makeCurrent()");
348  m_lock.unlock();
349 }
350 
352 {
353 #if !defined(Q_OS_WIN)
354  while (m_lock_level > 0)
355  doneCurrent();
356 #endif
357 }
358 
359 void MythRenderOpenGL::MoveResizeWindow(const QRect &rect)
360 {
361 #ifdef USE_OPENGL_QT5
362  QWindow *parent = m_window;
363 #else
364  QWidget *parent = dynamic_cast<QWidget* >(this->device());
365 #endif
366  if (parent)
367  parent->setGeometry(rect);
368 }
369 
370 void MythRenderOpenGL::SetViewPort(const QRect &rect, bool viewportonly)
371 {
372  if (rect == m_viewport)
373  return;
374  makeCurrent();
375  m_viewport = rect;
376  glViewport(m_viewport.left(), m_viewport.top(),
377  m_viewport.width(), m_viewport.height());
378  if (!viewportonly)
379  SetMatrixView();
380  doneCurrent();
381 }
382 
383 void MythRenderOpenGL::Flush(bool use_fence)
384 {
385  makeCurrent();
386 
387  if ((m_exts_used & kGLAppleFence) &&
388  (m_fence && use_fence))
389  {
392  }
393  else if ((m_exts_used & kGLNVFence) &&
394  (m_fence && use_fence))
395  {
398  }
399  else
400  {
401  if (m_flushEnabled)
402  glFlush();
403  }
404 
405  doneCurrent();
406 }
407 
408 void MythRenderOpenGL::SetBlend(bool enable)
409 {
410  makeCurrent();
411  if (enable && !m_blend)
412  glEnable(GL_BLEND);
413  else if (!enable && m_blend)
414  glDisable(GL_BLEND);
415  m_blend = enable;
416  doneCurrent();
417 }
418 
419 void MythRenderOpenGL::SetBackground(int r, int g, int b, int a)
420 {
421  uint32_t tmp = (r << 24) + (g << 16) + (b << 8) + a;
422  if (tmp == m_background)
423  return;
424 
425  m_background = tmp;
426  makeCurrent();
427  glClearColor(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
428  doneCurrent();
429 }
430 
432 {
433  makeCurrent();
435  {
437  if (m_fence)
438  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_APPLE_fence");
439  }
440  else if (m_exts_used & kGLNVFence)
441  {
443  if (m_fence)
444  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_NV_fence");
445  }
446  doneCurrent();
447 }
448 
449 void* MythRenderOpenGL::GetTextureBuffer(uint tex, bool create_buffer)
450 {
451  if (!m_textures.contains(tex))
452  return nullptr;
453 
454  makeCurrent(); // associated doneCurrent() in UpdateTexture
455 
456  EnableTextures(tex);
457  glBindTexture(m_textures[tex].m_type, tex);
458 
459  if (!create_buffer)
460  return nullptr;
461 
462  if (m_textures[tex].m_pbo)
463  {
466  m_textures[tex].m_data_size, nullptr, GL_STREAM_DRAW);
468  }
469 
470  if (m_textures[tex].m_data)
471  return m_textures[tex].m_data;
472 
473  unsigned char *scratch = new unsigned char[m_textures[tex].m_data_size];
474  if (scratch)
475  {
476  memset(scratch, 0, m_textures[tex].m_data_size);
477  m_textures[tex].m_data = scratch;
478  }
479  return scratch;
480 }
481 
483 {
484  // N.B. GetTextureBuffer must be called first
485  if (!m_textures.contains(tex))
486  return;
487 
488  QSize size = m_textures[tex].m_act_size;
489 
490  if (m_textures[tex].m_pbo)
491  {
493  glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
494  size.height(), m_textures[tex].m_data_fmt,
495  m_textures[tex].m_data_type, nullptr);
497  }
498  else
499  {
500  glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
501  size.height(), m_textures[tex].m_data_fmt,
502  m_textures[tex].m_data_type, buf);
503  }
504 
505  doneCurrent();
506 }
507 
509 {
510  static bool rects = true;
511  static bool check = true;
512  if (check)
513  {
514  check = false;
515  rects = !getenv("OPENGL_NORECT");
516  if (!rects)
517  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling NPOT textures.");
518  }
519 
520  int ret = GL_TEXTURE_2D;
521 
522  if (m_extensions.contains("GL_NV_texture_rectangle") && rects)
524  else if (m_extensions.contains("GL_ARB_texture_rectangle") && rects)
526  else if (m_extensions.contains("GL_EXT_texture_rectangle") && rects)
528 
529  rect = (ret != GL_TEXTURE_2D);
530  return ret;
531 }
532 
534 {
536  return true;
538  return true;
540  return true;
541  return false;
542 }
543 
544 uint MythRenderOpenGL::CreateTexture(QSize act_size, bool use_pbo,
545  uint type, uint data_type,
546  uint data_fmt, uint internal_fmt,
547  uint filter, uint wrap)
548 {
549 #ifdef USING_OPENGLES
550  //OPENGLES requires same formats for internal and external.
551  internal_fmt = data_fmt;
552  glCheck();
553 #endif
554 
555  if (!type)
557 
558  QSize tot_size = GetTextureSize(type, act_size);
559 
560  makeCurrent();
561 
562  EnableTextures(0, type);
563 
564  GLuint tex;
565  glGenTextures(1, &tex);
566  glBindTexture(type, tex);
567 
568  if (tex)
569  {
570  MythGLTexture texture;
571  texture.m_type = type;
572  texture.m_data_type = data_type;
573  texture.m_data_fmt = data_fmt;
574  texture.m_internal_fmt = internal_fmt;
575  texture.m_size = tot_size;
576  texture.m_act_size = act_size;
577  texture.m_data_size = GetBufferSize(act_size, data_fmt, data_type);
578  m_textures.insert(tex, texture);
579 
580  if (ClearTexture(tex) && m_textures[tex].m_data_size)
581  {
582  SetTextureFilters(tex, filter, wrap);
583  if (use_pbo)
584  m_textures[tex].m_pbo = CreatePBO(tex);
585  if (m_exts_used & kGLExtVBO)
586  m_textures[tex].m_vbo = CreateVBO();
587  }
588  else
589  {
590  DeleteTexture(tex);
591  tex = 0;
592  }
593  }
594 
595  Flush(true);
596  doneCurrent();
597 
598  return tex;
599 }
600 
602 {
603  makeCurrent();
604 
605  uint width = m_max_tex_size;
606  uint tmp_tex = CreateTexture(QSize(width, 1), false,
607  GL_TEXTURE_2D, GL_FLOAT, GL_RGBA,
608  GL_RGBA16, GL_NEAREST, GL_REPEAT);
609 
610  if (!tmp_tex)
611  {
612  DeleteTexture(tmp_tex);
613  return 0;
614  }
615 
616  float *buf = nullptr;
617  buf = new float[m_textures[tmp_tex].m_data_size];
618  float *ref = buf;
619 
620  for (uint i = 0; i < width; i++)
621  {
622  float x = (((float)i) + 0.5F) / (float)width;
623  StoreBicubicWeights(x, ref);
624  ref += 4;
625  }
626  StoreBicubicWeights(0, buf);
627  StoreBicubicWeights(1, &buf[(width - 1) << 2]);
628 
629  EnableTextures(tmp_tex);
630  glBindTexture(m_textures[tmp_tex].m_type, tmp_tex);
631  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, width, 1, 0, GL_RGBA, GL_FLOAT, buf);
632 
633  LOG(VB_PLAYBACK, LOG_INFO, LOC +
634  QString("Created bicubic helper texture (%1 samples)") .arg(width));
635  delete [] buf;
636  doneCurrent();
637  return tmp_tex;
638 }
639 
640 QSize MythRenderOpenGL::GetTextureSize(uint type, const QSize &size)
641 {
642  if (IsRectTexture(type))
643  return size;
644 
645  int w = 64;
646  int h = 64;
647 
648  while (w < size.width())
649  {
650  w *= 2;
651  }
652 
653  while (h < size.height())
654  {
655  h *= 2;
656  }
657 
658  return {w, h};
659 }
660 
662 {
663  if (!m_textures.contains(tex))
664  return {};
665  return m_textures[tex].m_size;
666 }
667 
669 {
670  if (!m_textures.contains(tex))
671  return 0;
672  return m_textures[tex].m_data_size;
673 }
674 
676 {
677  if (!m_textures.contains(tex))
678  return;
679 
680  bool mipmaps = ((m_exts_used & kGLMipMaps) != 0U) &&
682  if (filt == GL_LINEAR_MIPMAP_LINEAR && !mipmaps)
683  filt = GL_LINEAR;
684 
685  makeCurrent();
686  EnableTextures(tex);
687  m_textures[tex].m_filter = filt;
688  m_textures[tex].m_wrap = wrap;
689  uint type = m_textures[tex].m_type;
690  glBindTexture(type, tex);
691  uint mag_filt = filt;
692  if (filt == GL_LINEAR_MIPMAP_LINEAR)
693  {
694  mag_filt = GL_LINEAR;
695 #ifdef GL_GENERATE_MIPMAP_HINT_SGIS
696  glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
697 #endif
698 #ifdef GL_GENERATE_MIPMAP_SGIS
699  glTexParameteri(type, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
700 #endif
701  }
702  glTexParameteri(type, GL_TEXTURE_MIN_FILTER, filt);
703  glTexParameteri(type, GL_TEXTURE_MAG_FILTER, mag_filt);
704  glTexParameteri(type, GL_TEXTURE_WRAP_S, wrap);
705  glTexParameteri(type, GL_TEXTURE_WRAP_T, wrap);
706  doneCurrent();
707 }
708 
710 {
711  if (!(m_exts_used & kGLMultiTex))
712  return;
713 
714  makeCurrent();
715  if (m_active_tex != active_tex)
716  {
717  m_glActiveTexture(active_tex);
718  m_active_tex = active_tex;
719  }
720  doneCurrent();
721 }
722 
723 void MythRenderOpenGL::StoreBicubicWeights(float x, float *dst)
724 {
725  float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
726  float w1 = ((( 3 * x - 6) * x + 0) * x + 4) / 6;
727  float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
728  float w3 = ((( 1 * x + 0) * x + 0) * x + 0) / 6;
729  *dst++ = 1 + x - w1 / (w0 + w1);
730  *dst++ = 1 - x + w3 / (w2 + w3);
731  *dst++ = w0 + w1;
732  *dst++ = 0;
733 }
734 
736 {
737  if (tex && !m_textures.contains(tex))
738  return;
739 
740  makeCurrent();
741  int type = tex ? m_textures[tex].m_type : tex_type;
742  if (type != m_active_tex_type)
743  {
744 #ifndef USING_OPENGLES
745  if (m_active_tex_type)
746  glDisable(m_active_tex_type);
747  glEnable(type);
748 #endif
750  }
751  doneCurrent();
752 }
753 
755 {
756  if (!m_active_tex_type)
757  return;
758  makeCurrent();
759 #ifndef USING_OPENGLES
760  glDisable(m_active_tex_type);
761 #endif
762  m_active_tex_type = 0;
763  doneCurrent();
764 }
765 
767 {
768  if (!m_textures.contains(tex))
769  return;
770 
771  makeCurrent();
772 
773  GLuint gltex = tex;
774  glDeleteTextures(1, &gltex);
775  delete m_textures[tex].m_data;
776  if (m_textures[tex].m_pbo)
777  m_glDeleteBuffers(1, &(m_textures[tex].m_pbo));
778  if (m_textures[tex].m_vbo)
779  m_glDeleteBuffers(1, &(m_textures[tex].m_vbo));
780  m_textures.remove(tex);
781 
782  Flush(true);
783  doneCurrent();
784 }
785 
787 {
788  if (!(m_exts_used & kGLExtFBufObj))
789  return false;
790 
791  if (!m_textures.contains(tex))
792  return false;
793 
794  QSize size = m_textures[tex].m_size;
795  GLuint glfb;
796 
797  makeCurrent();
798  glCheck();
799 
800  EnableTextures(tex);
801  QRect tmp_viewport = m_viewport;
802  glViewport(0, 0, size.width(), size.height());
803  m_glGenFramebuffers(1, &glfb);
805  glBindTexture(m_textures[tex].m_type, tex);
806  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
807  size.width(), size.height(), 0,
808  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, nullptr);
810  m_textures[tex].m_type, tex, 0);
811 
812  GLenum status;
815  glViewport(tmp_viewport.left(), tmp_viewport.top(),
816  tmp_viewport.width(), tmp_viewport.height());
817 
818  bool success = false;
819  switch (status)
820  {
822  LOG(VB_PLAYBACK, LOG_INFO, LOC +
823  QString("Created frame buffer object (%1x%2).")
824  .arg(size.width()).arg(size.height()));
825  success = true;
826  break;
828  LOG(VB_PLAYBACK, LOG_INFO, LOC +
829  "Frame buffer incomplete_ATTACHMENT");
830  break;
832  LOG(VB_PLAYBACK, LOG_INFO, LOC +
833  "Frame buffer incomplete_MISSING_ATTACHMENT");
834  break;
836  LOG(VB_PLAYBACK, LOG_INFO, LOC +
837  "Frame buffer incomplete_DUPLICATE_ATTACHMENT");
838  break;
840  LOG(VB_PLAYBACK, LOG_INFO, LOC +
841  "Frame buffer incomplete_DIMENSIONS");
842  break;
844  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer incomplete_FORMATS");
845  break;
847  LOG(VB_PLAYBACK, LOG_INFO, LOC +
848  "Frame buffer incomplete_DRAW_BUFFER");
849  break;
851  LOG(VB_PLAYBACK, LOG_INFO, LOC +
852  "Frame buffer incomplete_READ_BUFFER");
853  break;
855  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer unsupported.");
856  break;
857  default:
858  LOG(VB_PLAYBACK, LOG_INFO, LOC +
859  QString("Unknown frame buffer error %1.").arg(status));
860  }
861 
862  if (success)
863  m_framebuffers.push_back(glfb);
864  else
865  m_glDeleteFramebuffers(1, &glfb);
866 
867  Flush(true);
868  glCheck();
869  doneCurrent();
870  fb = glfb;
871  return success;
872 }
873 
875 {
876  if (!m_framebuffers.contains(fb))
877  return;
878 
879  makeCurrent();
880  QVector<GLuint>::iterator it;
881  for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
882  {
883  if (*it == fb)
884  {
885  m_glDeleteFramebuffers(1, &(*it));
886  m_framebuffers.erase(it);
887  break;
888  }
889  }
890 
891  Flush(true);
892  doneCurrent();
893 }
894 
896 {
897  if (fb && !m_framebuffers.contains(fb))
898  return;
899 
900  if (fb == (uint)m_active_fb)
901  return;
902 
903  makeCurrent();
905  doneCurrent();
906  m_active_fb = fb;
907 }
908 
910 {
911  makeCurrent();
912  glClear(GL_COLOR_BUFFER_BIT);
913  doneCurrent();
914 }
915 
916 void MythRenderOpenGL::DrawBitmap(uint tex, uint target, const QRect *src,
917  const QRect *dst, uint prog, int alpha,
918  int red, int green, int blue)
919 {
920  if (!tex || !m_textures.contains(tex))
921  return;
922 
923  if (target && !m_framebuffers.contains(target))
924  target = 0;
925 
926  makeCurrent();
927  BindFramebuffer(target);
928  DrawBitmapPriv(tex, src, dst, prog, alpha, red, green, blue);
929  doneCurrent();
930 }
931 
932 void MythRenderOpenGL::DrawBitmap(uint *textures, uint texture_count,
933  uint target, const QRectF *src,
934  const QRectF *dst, uint prog)
935 {
936  if (!textures || !texture_count)
937  return;
938 
939  if (target && !m_framebuffers.contains(target))
940  target = 0;
941 
942  makeCurrent();
943  BindFramebuffer(target);
944  DrawBitmapPriv(textures, texture_count, src, dst, prog);
945  doneCurrent();
946 }
947 
948 void MythRenderOpenGL::DrawRect(const QRect &area, const QBrush &fillBrush,
949  const QPen &linePen, int alpha)
950 {
951  makeCurrent();
952  BindFramebuffer(0);
953  DrawRectPriv(area, fillBrush, linePen, alpha);
954  doneCurrent();
955 }
956 
957 void MythRenderOpenGL::DrawRoundRect(const QRect &area, int cornerRadius,
958  const QBrush &fillBrush,
959  const QPen &linePen, int alpha)
960 {
961  makeCurrent();
962  BindFramebuffer(0);
963  DrawRoundRectPriv(area, cornerRadius, fillBrush, linePen, alpha);
964  doneCurrent();
965 }
966 
968 {
969  SetBlend(false);
970  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
971  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
972  glDisable(GL_DEPTH_TEST);
973  glDepthMask(GL_FALSE);
974  glDisable(GL_CULL_FACE);
975  glClearColor(0.0F, 0.0F, 0.0F, 0.0F);
976  glClear(GL_COLOR_BUFFER_BIT);
977  Flush(true);
978 }
979 
981 {
982  m_extensions = (reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
983 
985  GetProcAddress("glActiveTexture");
987  GetProcAddress("glMapBuffer");
989  GetProcAddress("glBindBuffer");
991  GetProcAddress("glGenBuffers");
993  GetProcAddress("glBufferData");
995  GetProcAddress("glUnmapBuffer");
997  GetProcAddress("glDeleteBuffers");
999  GetProcAddress("glGenFramebuffers");
1001  GetProcAddress("glBindFramebuffer");
1003  GetProcAddress("glFramebufferTexture2D");
1005  GetProcAddress("glCheckFramebufferStatus");
1007  GetProcAddress("glDeleteFramebuffers");
1009  GetProcAddress("glGenFencesNV");
1011  GetProcAddress("glDeleteFencesNV");
1013  GetProcAddress("glSetFenceNV");
1015  GetProcAddress("glFinishFenceNV");
1017  GetProcAddress("glGenFencesAPPLE");
1019  GetProcAddress("glDeleteFencesAPPLE");
1021  GetProcAddress("glSetFenceAPPLE");
1023  GetProcAddress("glFinishFenceAPPLE");
1024 }
1025 
1026 void* MythRenderOpenGL::GetProcAddress(const QString &proc) const
1027 {
1028  // TODO FIXME - this should really return a void(*) not void*
1029  static const QString exts[4] = { "", "ARB", "EXT", "OES" };
1030  void *result;
1031  for (int i = 0; i < 4; i++)
1032  {
1033 #ifdef USING_OPENGLES
1034  result = reinterpret_cast<void*>(
1035  QLibrary::resolve("libGLESv2", (proc + exts[i]).toLatin1().data()));
1036  if (result)
1037  break;
1038 #else
1039  result = reinterpret_cast<void*>(getProcAddress(qPrintable(proc + exts[i])));
1040  if (result)
1041  break;
1042 #endif
1043  }
1044  if (result == nullptr)
1045  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1046  QString("Extension not found: %1").arg(proc));
1047 
1048  return result;
1049 }
1050 
1052 {
1053  static bool multitexture = true;
1054  static bool vertexarrays = true;
1055  static bool framebuffers = true;
1056  static bool pixelbuffers = true;
1057  static bool vertexbuffers = true;
1058  static bool fences = true;
1059  static bool ycbcrtextures = true;
1060  static bool mipmapping = true;
1061  static bool rgba16 = true;
1062  static bool check = true;
1063 
1064  if (check)
1065  {
1066  check = false;
1067  multitexture = !getenv("OPENGL_NOMULTITEX");
1068  vertexarrays = !getenv("OPENGL_NOVERTARRAY");
1069  framebuffers = !getenv("OPENGL_NOFBO");
1070  pixelbuffers = !getenv("OPENGL_NOPBO");
1071  vertexbuffers = !getenv("OPENGL_NOVBO");
1072  fences = !getenv("OPENGL_NOFENCE");
1073  ycbcrtextures = !getenv("OPENGL_NOYCBCR");
1074  mipmapping = !getenv("OPENGL_NOMIPMAP");
1075  rgba16 = !getenv("OPENGL_NORGBA16");
1076  if (!multitexture)
1077  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling multi-texturing.");
1078  if (!vertexarrays)
1079  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Arrays.");
1080  if (!framebuffers)
1081  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Framebuffer Objects.");
1082  if (!pixelbuffers)
1083  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Pixel Buffer Objects.");
1084  if (!vertexbuffers)
1085  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Buffer Objects.");
1086  if (!fences)
1087  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling fences.");
1088  if (!ycbcrtextures)
1089  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling YCbCr textures.");
1090  if (!mipmapping)
1091  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling mipmapping.");
1092  if (!rgba16)
1093  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling RGBA16 textures");
1094  }
1095 
1096  GLint maxtexsz = 0;
1097  GLint maxunits = 0;
1098  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsz);
1099  glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxunits);
1100  m_max_units = maxunits;
1101  m_max_tex_size = (maxtexsz) ? maxtexsz : 512;
1102 
1103  m_extensions = (const char*) glGetString(GL_EXTENSIONS);
1104  bool rects;
1106  if (rects)
1108 
1109  // GL 1.1
1110  if (rgba16)
1112 
1113  if (m_extensions.contains("GL_ARB_multitexture") &&
1114  m_glActiveTexture && multitexture)
1115  {
1117  if (m_max_units < 3)
1118  {
1119  LOG(VB_GENERAL, LOG_ERR, LOC +
1120  "Insufficient texture units for advanced OpenGL features.");
1121  }
1122  }
1123  else
1124  {
1125  LOG(VB_GENERAL, LOG_ERR, LOC + "Multi-texturing not supported. Certain "
1126  "OpenGL features will not work");
1127  }
1128 
1129  if (m_extensions.contains("GL_EXT_vertex_array") && vertexarrays)
1130  {
1132  }
1133  else
1134  {
1135  LOG(VB_GENERAL, LOG_ERR, LOC +
1136  "GL_EXT_vertex_array extension not supported. This may not work");
1137  }
1138 
1139  if (m_extensions.contains("GL_EXT_framebuffer_object") &&
1142  m_glCheckFramebufferStatus && framebuffers)
1144 
1145  bool buffer_procs = m_glMapBuffer && m_glBindBuffer &&
1148 
1149  if(m_extensions.contains("GL_ARB_pixel_buffer_object")
1150  && buffer_procs && pixelbuffers)
1152 
1153  if (m_extensions.contains("GL_ARB_vertex_buffer_object")
1154  && buffer_procs && vertexbuffers)
1156 
1157  if(m_extensions.contains("GL_NV_fence") &&
1159  m_glSetFenceNV && m_glFinishFenceNV && fences)
1161 
1162  if(m_extensions.contains("GL_APPLE_fence") &&
1166 
1167  if (m_extensions.contains("GL_MESA_ycbcr_texture") && ycbcrtextures)
1169 
1170  if (m_extensions.contains("GL_APPLE_ycbcr_422") && ycbcrtextures)
1172 
1173  if (m_extensions.contains("GL_SGIS_generate_mipmap") && mipmapping)
1175 
1176  static bool debugged = false;
1177  if (!debugged)
1178  {
1179  debugged = true;
1180  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL vendor : %1")
1181  .arg((const char*) glGetString(GL_VENDOR)));
1182  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL renderer: %1")
1183  .arg((const char*) glGetString(GL_RENDERER)));
1184  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL version : %1")
1185  .arg((const char*) glGetString(GL_VERSION)));
1186  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture size: %1 x %2")
1187  .arg(m_max_tex_size).arg(m_max_tex_size));
1188  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture units: %1")
1189  .arg(m_max_units));
1190  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Direct rendering: %1")
1191  .arg(IsDirectRendering() ? "Yes" : "No"));
1192  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Extensions Supported: %1")
1193  .arg(m_exts_supported, 0, 16));
1194  }
1195 
1197 
1198  if (m_exts_used & kGLExtPBufObj)
1199  {
1200  LOG(VB_GENERAL, LOG_INFO, LOC + "PixelBufferObject support available");
1201  }
1202 
1203  return true;
1204 }
1205 
1207 {
1208  m_fence = 0;
1209 
1210  m_lock_level = 0;
1211 
1212  m_extensions = QString();
1215  m_max_tex_size = 0;
1216  m_max_units = 0;
1217  m_default_texture_type = GL_TEXTURE_2D;
1218 
1219  m_viewport = QRect();
1220  m_active_tex = 0;
1221  m_active_tex_type = 0;
1222  m_active_fb = 0;
1223  m_blend = false;
1224  m_background = 0x00000000;
1225  m_flushEnabled = true;
1226 }
1227 
1229 {
1230  m_extensions = QString();
1231 
1232  m_glActiveTexture = nullptr;
1233  m_glMapBuffer = nullptr;
1234  m_glBindBuffer = nullptr;
1235  m_glGenBuffers = nullptr;
1236  m_glBufferData = nullptr;
1237  m_glUnmapBuffer = nullptr;
1238  m_glDeleteBuffers = nullptr;
1239  m_glGenFramebuffers = nullptr;
1240  m_glBindFramebuffer = nullptr;
1241  m_glFramebufferTexture2D = nullptr;
1242  m_glCheckFramebufferStatus = nullptr;
1243  m_glDeleteFramebuffers = nullptr;
1244  m_glGenFencesNV = nullptr;
1245  m_glDeleteFencesNV = nullptr;
1246  m_glSetFenceNV = nullptr;
1247  m_glFinishFenceNV = nullptr;
1248  m_glGenFencesAPPLE = nullptr;
1249  m_glDeleteFencesAPPLE = nullptr;
1250  m_glSetFenceAPPLE = nullptr;
1251  m_glFinishFenceAPPLE = nullptr;
1252 }
1253 
1255 {
1256  if (!(m_exts_used & kGLExtPBufObj))
1257  return 0;
1258 
1259  if (!m_textures.contains(tex))
1260  return 0;
1261 
1263  if (glCheck())
1264  {
1265  // looks like we dont support PBOs so dont bother doing the rest
1266  // and stop using it in the future
1267  LOG(VB_GENERAL, LOG_INFO, LOC + "Pixel Buffer Objects unusable, disabling");
1270  return 0;
1271  }
1272  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
1273  m_textures[tex].m_size.width(),
1274  m_textures[tex].m_size.height(), 0,
1275  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, nullptr);
1276 
1277  GLuint tmp_pbo;
1278  m_glGenBuffers(1, &tmp_pbo);
1280 
1281  Flush(true);
1282  return tmp_pbo;
1283 }
1284 
1286 {
1287  if (!(m_exts_used & kGLExtVBO))
1288  return 0;
1289 
1290  GLuint tmp_vbo;
1291  m_glGenBuffers(1, &tmp_vbo);
1292  return tmp_vbo;
1293 }
1294 
1296 {
1297  LOG(VB_GENERAL, LOG_INFO, LOC + "Deleting OpenGL Resources");
1298  DeleteTextures();
1300  Flush(true);
1301 
1302  if (m_fence)
1303  {
1306  else if(m_exts_supported & kGLNVFence)
1308  m_fence = 0;
1309  }
1310 
1311  Flush(false);
1312 
1313  ExpireVertices();
1314  ExpireVBOS();
1315 
1316  if (!m_cachedVertices.empty())
1317  {
1318  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired vertices")
1319  .arg(m_cachedVertices.size()));
1320  }
1321 
1322  if (!m_cachedVBOS.empty())
1323  {
1324  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired VBOs")
1325  .arg(m_cachedVertices.size()));
1326  }
1327 }
1328 
1330 {
1331  QHash<GLuint, MythGLTexture>::iterator it;
1332  for (it = m_textures.begin(); it !=m_textures.end(); ++it)
1333  {
1334  glDeleteTextures(1, &(it.key()));
1335  delete it.value().m_data;
1336  if (it.value().m_pbo)
1337  m_glDeleteBuffers(1, &(it.value().m_pbo));
1338  }
1339  m_textures.clear();
1340  Flush(true);
1341 }
1342 
1344 {
1345  QVector<GLuint>::iterator it;
1346  for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
1347  m_glDeleteFramebuffers(1, &(*(it)));
1348  m_framebuffers.clear();
1349  Flush(true);
1350 }
1351 
1353  const QRect *dst)
1354 {
1355  if (!m_textures.contains(tex))
1356  return false;
1357 
1358  GLfloat *data = m_textures[tex].m_vertex_data;
1359  QSize size = m_textures[tex].m_size;
1360 
1361  int width = min(src->width(), size.width());
1362  int height = min(src->height(), size.height());
1363 
1364  data[0 + TEX_OFFSET] = src->left();
1365  data[1 + TEX_OFFSET] = src->top() + height;
1366 
1367  data[6 + TEX_OFFSET] = src->left() + width;
1368  data[7 + TEX_OFFSET] = src->top();
1369 
1370  if (!IsRectTexture(m_textures[tex].m_type))
1371  {
1372  data[0 + TEX_OFFSET] /= (float)size.width();
1373  data[6 + TEX_OFFSET] /= (float)size.width();
1374  data[1 + TEX_OFFSET] /= (float)size.height();
1375  data[7 + TEX_OFFSET] /= (float)size.height();
1376  }
1377 
1378  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1379  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1380  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1381  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1382 
1383  data[2] = data[0] = dst->left();
1384  data[5] = data[1] = dst->top();
1385  data[4] = data[6] = dst->left() + min(width, dst->width());
1386  data[3] = data[7] = dst->top() + min(height, dst->height());
1387 
1388  return true;
1389 }
1390 
1391 bool MythRenderOpenGL::UpdateTextureVertices(uint tex, const QRectF *src,
1392  const QRectF *dst)
1393 {
1394  if (!m_textures.contains(tex))
1395  return false;
1396 
1397  GLfloat *data = m_textures[tex].m_vertex_data;
1398 
1399  data[0 + TEX_OFFSET] = src->left();
1400  data[1 + TEX_OFFSET] = src->top() + src->height();
1401 
1402  data[6 + TEX_OFFSET] = src->left() + src->width();
1403  data[7 + TEX_OFFSET] = src->top();
1404 
1405  if (!IsRectTexture(m_textures[tex].m_type))
1406  {
1407  data[0 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
1408  data[6 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
1409  data[1 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
1410  data[7 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
1411  }
1412 
1413  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1414  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1415  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1416  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1417 
1418  data[2] = data[0] = dst->left();
1419  data[5] = data[1] = dst->top();
1420  data[4] = data[6] = dst->left() + dst->width();
1421  data[3] = data[7] = dst->top() + dst->height();
1422 
1423  return true;
1424 }
1425 
1426 GLfloat* MythRenderOpenGL::GetCachedVertices(GLuint type, const QRect &area)
1427 {
1428  uint64_t ref = ((uint64_t)area.left() & 0xfff) +
1429  (((uint64_t)area.top() & 0xfff) << 12) +
1430  (((uint64_t)area.width() & 0xfff) << 24) +
1431  (((uint64_t)area.height() & 0xfff) << 36) +
1432  (((uint64_t)type & 0xfff) << 48);
1433 
1434  if (m_cachedVertices.contains(ref))
1435  {
1436  m_vertexExpiry.removeOne(ref);
1437  m_vertexExpiry.append(ref);
1438  return m_cachedVertices[ref];
1439  }
1440 
1441  GLfloat *vertices = new GLfloat[8];
1442 
1443  vertices[2] = vertices[0] = area.left();
1444  vertices[5] = vertices[1] = area.top();
1445  vertices[4] = vertices[6] = area.left() + area.width();
1446  vertices[3] = vertices[7] = area.top() + area.height();
1447 
1448  if (type == GL_LINE_LOOP)
1449  {
1450  vertices[7] = vertices[1];
1451  vertices[5] = vertices[3];
1452  }
1453 
1454  m_cachedVertices.insert(ref, vertices);
1455  m_vertexExpiry.append(ref);
1457 
1458  return vertices;
1459 }
1460 
1462 {
1463  while ((uint)m_vertexExpiry.size() > max)
1464  {
1465  uint64_t ref = m_vertexExpiry.first();
1466  m_vertexExpiry.removeFirst();
1467  GLfloat *vertices = nullptr;
1468  if (m_cachedVertices.contains(ref))
1469  vertices = m_cachedVertices.value(ref);
1470  m_cachedVertices.remove(ref);
1471  delete [] vertices;
1472  }
1473 }
1474 
1475 void MythRenderOpenGL::GetCachedVBO(GLuint type, const QRect &area)
1476 {
1477  uint64_t ref = ((uint64_t)area.left() & 0xfff) +
1478  (((uint64_t)area.top() & 0xfff) << 12) +
1479  (((uint64_t)area.width() & 0xfff) << 24) +
1480  (((uint64_t)area.height() & 0xfff) << 36) +
1481  (((uint64_t)type & 0xfff) << 48);
1482 
1483  if (m_cachedVBOS.contains(ref))
1484  {
1485  m_vboExpiry.removeOne(ref);
1486  m_vboExpiry.append(ref);
1487  }
1488  else
1489  {
1490  GLfloat *vertices = GetCachedVertices(type, area);
1491  GLuint vbo = CreateVBO();
1492  m_cachedVBOS.insert(ref, vbo);
1493  m_vboExpiry.append(ref);
1494 
1496  if (m_exts_used & kGLExtPBufObj)
1497  {
1499  void* target = m_glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
1500  if (target)
1501  memcpy(target, vertices, kTextureOffset);
1503  }
1504  else
1505  {
1507  }
1509  return;
1510  }
1511 
1513 }
1514 
1516 {
1517  while ((uint)m_vboExpiry.size() > max)
1518  {
1519  uint64_t ref = m_vboExpiry.first();
1520  m_vboExpiry.removeFirst();
1521  if (m_cachedVBOS.contains(ref))
1522  {
1523  GLuint vbo = m_cachedVBOS.value(ref);
1524  m_glDeleteBuffers(1, &vbo);
1525  m_cachedVBOS.remove(ref);
1526  }
1527  }
1528 }
1529 
1531 {
1532  if (!m_textures.contains(tex))
1533  return false;
1534 
1535  QSize size = m_textures[tex].m_size;
1536  uint tmp_size = GetBufferSize(size, m_textures[tex].m_data_fmt,
1537  m_textures[tex].m_data_type);
1538 
1539  if (!tmp_size)
1540  return false;
1541 
1542  unsigned char *scratch = new unsigned char[tmp_size];
1543 
1544  if (!scratch)
1545  return false;
1546 
1547  memset(scratch, 0, tmp_size);
1548 
1549  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
1550  size.width(), size.height(), 0, m_textures[tex].m_data_fmt,
1551  m_textures[tex].m_data_type, scratch);
1552  delete [] scratch;
1553 
1554  if (glCheck())
1555  {
1556  LOG(VB_GENERAL, LOG_ERR, LOC + QString("glTexImage size %1 failed")
1557  .arg(tmp_size));
1558  return false;
1559  }
1560 
1561  return true;
1562 }
1563 
1565 {
1566  uint bytes;
1567  uint bpp;
1568 
1569  if (fmt ==GL_RGBA)
1570  {
1571  bpp = 4;
1572  }
1573  else if (fmt == GL_RGB)
1574  {
1575  bpp = 3;
1576  }
1577  else if (fmt == GL_YCBCR_MESA || fmt == GL_YCBCR_422_APPLE)
1578  {
1579  bpp = 2;
1580  }
1581  else if (fmt == GL_LUMINANCE || fmt == GL_ALPHA)
1582  {
1583  bpp = 1;
1584  }
1585  else
1586  {
1587  bpp =0;
1588  }
1589 
1590  switch (type)
1591  {
1592  case GL_UNSIGNED_BYTE:
1593  bytes = sizeof(GLubyte);
1594  break;
1595 #ifdef GL_UNSIGNED_SHORT_8_8_MESA
1597  bytes = sizeof(GLushort);
1598  break;
1599 #endif
1600  case GL_FLOAT:
1601  bytes = sizeof(GLfloat);
1602  break;
1603  default:
1604  bytes = 0;
1605  }
1606 
1607  if (!bpp || !bytes || size.width() < 1 || size.height() < 1)
1608  return 0;
1609 
1610  return size.width() * size.height() * bpp * bytes;
1611 }
void DrawRoundRect(const QRect &area, int cornerRadius, const QBrush &fillBrush, const QPen &linePen, int alpha)
void(APIENTRY * MYTH_GLBUFFERDATAPROC)(GLenum target, MYTH_GLsizeiptr size, const GLvoid *data, GLenum usage)
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
#define GL_FRAMEBUFFER
MYTH_GLDELETEFRAMEBUFFERSPROC m_glDeleteFramebuffers
void SetBlend(bool enable)
GLvoid *(APIENTRY * MYTH_GLMAPBUFFERPROC)(GLenum target, GLenum access)
void setWidget(QGLWidget *w)
#define GL_ALL_COMPLETED_NV
#define glCheck()
MYTH_GLSETFENCEAPPLEPROC m_glSetFenceAPPLE
void DeleteTexture(uint tex)
void(* MYTH_GLDELETEFENCESAPPLEPROC)(GLsizei n, const GLuint *fences)
static void StoreBicubicWeights(float x, float *dst)
MYTH_GLBUFFERDATAPROC m_glBufferData
int GetTextureDataSize(uint tex)
static void error(const char *str,...)
Definition: vbi.c:42
MYTH_GLMAPBUFFERPROC m_glMapBuffer
MYTH_GLGENFRAMEBUFFERSPROC m_glGenFramebuffers
QList< uint64_t > m_vertexExpiry
MYTH_GLBINDBUFFERPROC m_glBindBuffer
uint GetBufferSize(QSize size, uint fmt, uint type)
MYTH_GLDELETEBUFFERSPROC m_glDeleteBuffers
GLenum(APIENTRY * MYTH_GLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target)
void GetCachedVBO(GLuint type, const QRect &area)
#define GL_WRITE_ONLY
void(APIENTRY * MYTH_GLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers)
#define GL_MAX_TEXTURE_UNITS
void(* MYTH_GLSETFENCEAPPLEPROC)(GLuint fence)
unsigned int uint
Definition: compat.h:140
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
virtual void DrawRoundRectPriv(const QRect &area, int cornerRadius, const QBrush &fillBrush, const QPen &linePen, int alpha)=0
static guint32 * tmp
Definition: goom_core.c:35
GLboolean(APIENTRY * MYTH_GLUNMAPBUFFERPROC)(GLenum target)
#define GL_RGBA16
MYTH_GLGENFENCESNVPROC m_glGenFencesNV
void ExpireVertices(uint max=0)
QSize GetTextureSize(uint type, const QSize &size)
unsigned char r
Definition: ParseText.cpp:329
uint CreatePBO(uint tex)
QVector< GLuint > m_framebuffers
void SetBackground(int r, int g, int b, int a)
#define OPENGL2_PAINTER
Definition: mythuidefines.h:4
RenderType m_type
void DrawBitmap(uint tex, uint target, const QRect *src, const QRect *dst, uint prog, int alpha=255, int red=255, int green=255, int blue=255)
unsigned char b
Definition: ParseText.cpp:329
bool IsDirectRendering() const
QList< uint64_t > m_vboExpiry
void * GetProcAddress(const QString &proc) const
QMap< uint64_t, GLfloat * > m_cachedVertices
MYTH_GLFINISHFENCEAPPLEPROC m_glFinishFenceAPPLE
void(APIENTRY * MYTH_GLSETFENCENVPROC)(GLuint fence, GLenum condition)
void Flush(bool use_fence)
MYTH_GLGENFENCESAPPLEPROC m_glGenFencesAPPLE
void doneCurrent() override
#define GL_STREAM_DRAW
void(APIENTRY * MYTH_GLDELETEFENCESNVPROC)(GLsizei n, const GLuint *fences)
#define GL_TEXTURE_RECTANGLE_EXT
void(APIENTRY * MYTH_GLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
#define GL_YCBCR_MESA
static int __glCheck__(const QString &loc, const char *fileName, int n)
MYTH_GLFINISHFENCENVPROC m_glFinishFenceNV
MYTH_GLFRAMEBUFFERTEXTURE2DPROC m_glFramebufferTexture2D
#define TEX_OFFSET
void SetTextureFilters(uint tex, uint filt, uint wrap)
int CheckNVOpenGLSyncToVBlank(void)
Definition: util-nvctrl.cpp:39
static const GLuint kTextureOffset
MYTH_GLUNMAPBUFFERPROC m_glUnmapBuffer
virtual bool InitFeatures(void)
void(APIENTRY * MYTH_GLACTIVETEXTUREPROC)(GLenum texture)
MYTH_GLDELETEFENCESAPPLEPROC m_glDeleteFencesAPPLE
void DeleteFrameBuffer(uint fb)
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
#define GL_COLOR_ATTACHMENT0
MYTH_GLSETFENCENVPROC m_glSetFenceNV
MYTH_GLCHECKFRAMEBUFFERSTATUSPROC m_glCheckFramebufferStatus
class QGLFormat MythRenderFormat
uint CreateHelperTexture(void)
void(* MYTH_GLFINISHFENCEAPPLEPROC)(GLuint fence)
void DrawRect(const QRect &area, const QBrush &fillBrush, const QPen &linePen, int alpha)
void UpdateTexture(uint tex, void *buf)
#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
#define GL_ARRAY_BUFFER
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
virtual void DrawRectPriv(const QRect &area, const QBrush &fillBrush, const QPen &linePen, int alpha)=0
void MoveResizeWindow(const QRect &rect)
QHash< GLuint, MythGLTexture > m_textures
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS
#define GL_GENERATE_MIPMAP_SGIS
void(APIENTRY * MYTH_GLFINISHFENCENVPROC)(GLuint fence)
virtual void SetMatrixView(void)=0
void ExpireVBOS(uint max=0)
#define GL_FRAMEBUFFER_COMPLETE
void * GetTextureBuffer(uint tex, bool create_buffer=true)
void makeCurrent() override
bool ClearTexture(uint tex)
bool CreateFrameBuffer(uint &fb, uint tex)
#define GL_GENERATE_MIPMAP_HINT_SGIS
void SetViewPort(const QRect &rect, bool viewportonly=false)
void(APIENTRY * MYTH_GLGENFENCESNVPROC)(GLsizei n, GLuint *fences)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
MythRenderOpenGL * m_render
#define MAX_VERTEX_CACHE
GLfloat * GetCachedVertices(GLuint type, const QRect &area)
void ActiveTexture(int active_tex)
#define GL_YCBCR_422_APPLE
#define GL_RGBA
int GetTextureType(bool &rect)
#define LOC
MYTH_GLGENBUFFERSPROC m_glGenBuffers
OpenGLLocker(MythRenderOpenGL *render)
#define GL_UNSIGNED_SHORT_8_8_MESA
void(APIENTRY * MYTH_GLBINDBUFFERPROC)(GLenum target, GLuint buffer)
#define GL_TEXTURE_RECTANGLE_NV
MythRenderOpenGL(const MythRenderFormat &format, QPaintDevice *device, RenderType type=kRenderUnknown)
MYTH_GLACTIVETEXTUREPROC m_glActiveTexture
void EnableTextures(uint tex, uint tex_type=0)
#define GL_TEXTURE_RECTANGLE_ARB
#define GL_PIXEL_UNPACK_BUFFER
static MythRenderOpenGL * Create(const QString &painter, QPaintDevice *device=nullptr)
void(* MYTH_GLGENFENCESAPPLEPROC)(GLsizei n, GLuint *fences)
virtual void ResetVars(void)
#define AUTO_PAINTER
Definition: mythuidefines.h:5
RenderType
uint CreateTexture(QSize act_size, bool use_pbo, uint type, uint data_type=GL_UNSIGNED_BYTE, uint data_fmt=GL_RGBA, uint internal_fmt=GL_RGBA8, uint filter=GL_LINEAR, uint wrap=GL_CLAMP_TO_EDGE)
bool IsRectTexture(uint type)
virtual void Init2DState(void)
virtual void ResetProcs(void)
void(APIENTRY * MYTH_GLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers)
MYTH_GLBINDFRAMEBUFFERPROC m_glBindFramebuffer
QMap< uint64_t, GLuint > m_cachedVBOS
MYTH_GLDELETEFENCESNVPROC m_glDeleteFencesNV
#define GL_FRAMEBUFFER_UNSUPPORTED
void(APIENTRY * MYTH_GLGENBUFFERSPROC)(GLsizei n, GLuint *buffers)
void(APIENTRY * MYTH_GLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers)
void Release(void) override
void BindFramebuffer(uint fb)
bool UpdateTextureVertices(uint tex, const QRect *src, const QRect *dst)
bool IsRecommendedRenderer(void)
virtual void DrawBitmapPriv(uint tex, const QRect *src, const QRect *dst, uint prog, int alpha, int red, int green, int blue)=0
virtual void DeleteOpenGLResources(void)
virtual void InitProcs(void)
unsigned char g
Definition: ParseText.cpp:329
void(APIENTRY * MYTH_GLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer)