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  QGLWidget *dummy = new QGLWidget;
134  dummy->makeCurrent();
135  QGLFormat qglFormat = dummy->format();
136  int openGLVersionFlags = qglFormat.openGLVersionFlags();
137  delete dummy;
138 #endif
139 
140 #ifdef USING_OPENGLES
141  Q_UNUSED(painter);
142  if (!(openGLVersionFlags & QGLFormat::OpenGL_ES_Version_2_0))
143  {
144  LOG(VB_GENERAL, LOG_WARNING,
145  "Using OpenGL ES 2.0 render, however OpenGL ES 2.0 "
146  "version not supported");
147  }
148  if (device)
149  return new MythRenderOpenGL2ES(format, device);
150  return new MythRenderOpenGL2ES(format);
151 #else
152  if ((openGLVersionFlags & QGLFormat::OpenGL_Version_2_0) &&
153  (painter.contains(OPENGL2_PAINTER) || painter.contains(AUTO_PAINTER) ||
154  painter.isEmpty()))
155  {
156  LOG(VB_GENERAL, LOG_INFO, "Trying the OpenGL 2.0 render");
157  format.setVersion(2,0);
158  if (device)
159  return new MythRenderOpenGL2(format, device);
160  return new MythRenderOpenGL2(format);
161  }
162 
163  if (!(openGLVersionFlags & QGLFormat::OpenGL_Version_1_2))
164  {
165  LOG(VB_GENERAL, LOG_WARNING, "OpenGL 1.2 not supported, get new hardware!");
166  return nullptr;
167  }
168 
169  LOG(VB_GENERAL, LOG_INFO, "Trying the OpenGL 1.2 render");
170  format.setVersion(1,3);
171  if (device)
172  return new MythRenderOpenGL1(format, device);
173  return new MythRenderOpenGL1(format);
174 
175 #endif
176 }
177 
178 #ifdef USE_OPENGL_QT5
179 MythRenderOpenGL::MythRenderOpenGL(const MythRenderFormat& format, QPaintDevice* device,
181  : MythRender(type), m_lock(QMutex::Recursive)
182 {
183  QWidget *w = dynamic_cast<QWidget*>(device);
184  m_window = (w) ? w->windowHandle() : nullptr;
185  ResetVars();
186  ResetProcs();
187  setFormat(format);
188 }
189 
191  : MythRender(type), m_lock(QMutex::Recursive), m_window(nullptr)
192 {
193  ResetVars();
194  ResetProcs();
195  setFormat(format);
196 }
197 #else
198 MythRenderOpenGL::MythRenderOpenGL(const MythRenderFormat& format, QPaintDevice* device,
200  : QGLContext(format, device), MythRender(type), m_lock(QMutex::Recursive)
201 {
202  ResetVars();
203  ResetProcs();
204 }
205 
207  : QGLContext(format), MythRender(type), m_lock(QMutex::Recursive)
208 {
209  ResetVars();
210  ResetProcs();
211 }
212 #endif
213 
215 {
216  if (!isValid())
217  {
218  LOG(VB_GENERAL, LOG_ERR, LOC + "Init an invalid context."
219  " Missing call to setWidget or create?");
220  return;
221  }
222 
223  OpenGLLocker locker(this);
224  InitProcs();
225  Init2DState();
226  InitFeatures();
227 
228  LOG(VB_GENERAL, LOG_INFO, LOC + "Initialised MythRenderOpenGL");
229 }
230 
232 {
233  bool recommended = true;
234  OpenGLLocker locker(this);
235  QString renderer = (const char*) glGetString(GL_RENDERER);
236 
237  if (!IsDirectRendering())
238  {
239  LOG(VB_GENERAL, LOG_WARNING, LOC +
240  "OpenGL is using software rendering.");
241  recommended = false;
242  }
243  else
244  if (renderer.contains("Software Rasterizer", Qt::CaseInsensitive))
245  {
246  LOG(VB_GENERAL, LOG_WARNING, LOC +
247  "OpenGL is using software rasterizer.");
248  recommended = false;
249  }
250  else if (renderer.contains("softpipe", Qt::CaseInsensitive))
251  {
252  LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL seems to be using software "
253  "fallback. Please check your OpenGL driver installation, "
254  "configuration, and device permissions.");
255  recommended = false;
256  }
257  return recommended;
258 }
259 
260 #ifdef USE_OPENGL_QT5
262 {
263  return QGLFormat::fromSurfaceFormat(format()).directRendering();
264 }
265 
266 void MythRenderOpenGL::swapBuffers()
267 {
268  QOpenGLContext::swapBuffers(m_window);
269 }
270 
271 void MythRenderOpenGL::setWidget(QWidget *w)
272 {
273  if (!w)
274  return;
275 
276  w->winId(); // Ensure native window
277  m_window = w->windowHandle();
278  if (!m_window)
279  {
280  w = w->nativeParentWidget();
281  if (w)
282  m_window = w->windowHandle();
283  }
284 
285 #ifdef ANDROID
286  // change all window surfacetypes to OpenGLSurface
287  // otherwise the raster gets painted on top of the GL surface
288  m_window->setSurfaceType(QWindow::OpenGLSurface);
289  QWidget* wNativeParent = w->nativeParentWidget();
290  if (wNativeParent)
291  wNativeParent->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
292 #endif
293 
294  if (!create())
295  LOG(VB_GENERAL, LOG_WARNING, LOC + "setWidget create failed");
296  else if (w)
297  w->setAttribute(Qt::WA_PaintOnScreen);
298 }
299 #else
301 {
302  return format().directRendering();
303 }
304 
305 void MythRenderOpenGL::setWidget(QGLWidget *w)
306 {
307  setDevice(w);
308 
309 #ifdef ANDROID
310  // change all window surfacetypes to OpenGLSurface
311  // otherwise the raster gets painted on top of the GL surface
312  m_window->setSurfaceType(QWindow::OpenGLSurface);
313  QWidget* wNativeParent = w->nativeParentWidget();
314  if (wNativeParent)
315  wNativeParent->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
316 #endif
317 
318  w->setContext(this);
319 }
320 #endif
321 
323 {
324  m_lock.lock();
325 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
326  // Testing MythRenderOpenGL::currentContext is not reliable
327  if (!m_lock_level++)
328  {
329 #ifdef USE_OPENGL_QT5
330  QOpenGLContext::makeCurrent(m_window);
331 #else
332  QGLContext::makeCurrent();
333 #endif
334  }
335 #else
336  if (this != MythRenderOpenGL::currentContext())
337  QGLContext::makeCurrent();
338  m_lock_level++;
339  #endif
340 }
341 
343 {
344  m_lock_level--;
345  // Calling doneCurrent is strictly not necessary and causes the next call
346  // to makeCurrent to take considerably longer
347 #if 0
348  if (m_lock_level == 0)
349  QGLContext::doneCurrent();
350 #endif
351  if (m_lock_level < 0)
352  LOG(VB_GENERAL, LOG_ERR, LOC + "Mis-matched calls to makeCurrent()");
353  m_lock.unlock();
354 }
355 
357 {
358 #if !defined(Q_OS_WIN)
359  while (m_lock_level > 0)
360  doneCurrent();
361 #endif
362 }
363 
364 void MythRenderOpenGL::MoveResizeWindow(const QRect &rect)
365 {
366 #ifdef USE_OPENGL_QT5
367  QWindow *parent = m_window;
368 #else
369  QWidget *parent = dynamic_cast<QWidget* >(this->device());
370 #endif
371  if (parent)
372  parent->setGeometry(rect);
373 }
374 
375 void MythRenderOpenGL::SetViewPort(const QRect &rect, bool viewportonly)
376 {
377  if (rect == m_viewport)
378  return;
379  makeCurrent();
380  m_viewport = rect;
381  glViewport(m_viewport.left(), m_viewport.top(),
382  m_viewport.width(), m_viewport.height());
383  if (!viewportonly)
384  SetMatrixView();
385  doneCurrent();
386 }
387 
388 void MythRenderOpenGL::Flush(bool use_fence)
389 {
390  makeCurrent();
391 
392  if ((m_exts_used & kGLAppleFence) &&
393  (m_fence && use_fence))
394  {
397  }
398  else if ((m_exts_used & kGLNVFence) &&
399  (m_fence && use_fence))
400  {
403  }
404  else
405  {
406  if (m_flushEnabled)
407  glFlush();
408  }
409 
410  doneCurrent();
411 }
412 
413 void MythRenderOpenGL::SetBlend(bool enable)
414 {
415  makeCurrent();
416  if (enable && !m_blend)
417  glEnable(GL_BLEND);
418  else if (!enable && m_blend)
419  glDisable(GL_BLEND);
420  m_blend = enable;
421  doneCurrent();
422 }
423 
424 void MythRenderOpenGL::SetBackground(int r, int g, int b, int a)
425 {
426  uint32_t tmp = (r << 24) + (g << 16) + (b << 8) + a;
427  if (tmp == m_background)
428  return;
429 
430  m_background = tmp;
431  makeCurrent();
432  glClearColor(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
433  doneCurrent();
434 }
435 
437 {
438  makeCurrent();
440  {
442  if (m_fence)
443  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_APPLE_fence");
444  }
445  else if (m_exts_used & kGLNVFence)
446  {
448  if (m_fence)
449  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_NV_fence");
450  }
451  doneCurrent();
452 }
453 
454 void* MythRenderOpenGL::GetTextureBuffer(uint tex, bool create_buffer)
455 {
456  if (!m_textures.contains(tex))
457  return nullptr;
458 
459  makeCurrent(); // associated doneCurrent() in UpdateTexture
460 
461  EnableTextures(tex);
462  glBindTexture(m_textures[tex].m_type, tex);
463 
464  if (!create_buffer)
465  return nullptr;
466 
467  if (m_textures[tex].m_pbo)
468  {
471  m_textures[tex].m_data_size, nullptr, GL_STREAM_DRAW);
473  }
474 
475  if (m_textures[tex].m_data)
476  return m_textures[tex].m_data;
477 
478  unsigned char *scratch = new unsigned char[m_textures[tex].m_data_size];
479  if (scratch)
480  {
481  memset(scratch, 0, m_textures[tex].m_data_size);
482  m_textures[tex].m_data = scratch;
483  }
484  return scratch;
485 }
486 
488 {
489  // N.B. GetTextureBuffer must be called first
490  if (!m_textures.contains(tex))
491  return;
492 
493  QSize size = m_textures[tex].m_act_size;
494 
495  if (m_textures[tex].m_pbo)
496  {
498  glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
499  size.height(), m_textures[tex].m_data_fmt,
500  m_textures[tex].m_data_type, nullptr);
502  }
503  else
504  {
505  glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
506  size.height(), m_textures[tex].m_data_fmt,
507  m_textures[tex].m_data_type, buf);
508  }
509 
510  doneCurrent();
511 }
512 
514 {
515  static bool rects = true;
516  static bool check = true;
517  if (check)
518  {
519  check = false;
520  rects = !getenv("OPENGL_NORECT");
521  if (!rects)
522  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling NPOT textures.");
523  }
524 
525  int ret = GL_TEXTURE_2D;
526 
527  if (m_extensions.contains("GL_NV_texture_rectangle") && rects)
529  else if (m_extensions.contains("GL_ARB_texture_rectangle") && rects)
531  else if (m_extensions.contains("GL_EXT_texture_rectangle") && rects)
533 
534  rect = (ret != GL_TEXTURE_2D);
535  return ret;
536 }
537 
539 {
541  return true;
543  return true;
545  return true;
546  return false;
547 }
548 
549 uint MythRenderOpenGL::CreateTexture(QSize act_size, bool use_pbo,
550  uint type, uint data_type,
551  uint data_fmt, uint internal_fmt,
552  uint filter, uint wrap)
553 {
554 #ifdef USING_OPENGLES
555  //OPENGLES requires same formats for internal and external.
556  internal_fmt = data_fmt;
557  glCheck();
558 #endif
559 
560  if (!type)
562 
563  QSize tot_size = GetTextureSize(type, act_size);
564 
565  makeCurrent();
566 
567  EnableTextures(0, type);
568 
569  GLuint tex;
570  glGenTextures(1, &tex);
571  glBindTexture(type, tex);
572 
573  if (tex)
574  {
575  MythGLTexture texture;
576  texture.m_type = type;
577  texture.m_data_type = data_type;
578  texture.m_data_fmt = data_fmt;
579  texture.m_internal_fmt = internal_fmt;
580  texture.m_size = tot_size;
581  texture.m_act_size = act_size;
582  texture.m_data_size = GetBufferSize(act_size, data_fmt, data_type);
583  m_textures.insert(tex, texture);
584 
585  if (ClearTexture(tex) && m_textures[tex].m_data_size)
586  {
587  SetTextureFilters(tex, filter, wrap);
588  if (use_pbo)
589  m_textures[tex].m_pbo = CreatePBO(tex);
590  if (m_exts_used & kGLExtVBO)
591  m_textures[tex].m_vbo = CreateVBO();
592  }
593  else
594  {
595  DeleteTexture(tex);
596  tex = 0;
597  }
598  }
599 
600  Flush(true);
601  doneCurrent();
602 
603  return tex;
604 }
605 
607 {
608  makeCurrent();
609 
610  uint width = m_max_tex_size;
611  uint tmp_tex = CreateTexture(QSize(width, 1), false,
612  GL_TEXTURE_2D, GL_FLOAT, GL_RGBA,
613  GL_RGBA16, GL_NEAREST, GL_REPEAT);
614 
615  if (!tmp_tex)
616  {
617  DeleteTexture(tmp_tex);
618  return 0;
619  }
620 
621  float *buf = nullptr;
622  buf = new float[m_textures[tmp_tex].m_data_size];
623  float *ref = buf;
624 
625  for (uint i = 0; i < width; i++)
626  {
627  float x = (((float)i) + 0.5f) / (float)width;
628  StoreBicubicWeights(x, ref);
629  ref += 4;
630  }
631  StoreBicubicWeights(0, buf);
632  StoreBicubicWeights(1, &buf[(width - 1) << 2]);
633 
634  EnableTextures(tmp_tex);
635  glBindTexture(m_textures[tmp_tex].m_type, tmp_tex);
636  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, width, 1, 0, GL_RGBA, GL_FLOAT, buf);
637 
638  LOG(VB_PLAYBACK, LOG_INFO, LOC +
639  QString("Created bicubic helper texture (%1 samples)") .arg(width));
640  delete [] buf;
641  doneCurrent();
642  return tmp_tex;
643 }
644 
645 QSize MythRenderOpenGL::GetTextureSize(uint type, const QSize &size)
646 {
647  if (IsRectTexture(type))
648  return size;
649 
650  int w = 64;
651  int h = 64;
652 
653  while (w < size.width())
654  {
655  w *= 2;
656  }
657 
658  while (h < size.height())
659  {
660  h *= 2;
661  }
662 
663  return QSize(w, h);
664 }
665 
667 {
668  if (!m_textures.contains(tex))
669  return QSize();
670  return m_textures[tex].m_size;
671 }
672 
674 {
675  if (!m_textures.contains(tex))
676  return 0;
677  return m_textures[tex].m_data_size;
678 }
679 
681 {
682  if (!m_textures.contains(tex))
683  return;
684 
685  bool mipmaps = (m_exts_used & kGLMipMaps) &&
687  if (filt == GL_LINEAR_MIPMAP_LINEAR && !mipmaps)
688  filt = GL_LINEAR;
689 
690  makeCurrent();
691  EnableTextures(tex);
692  m_textures[tex].m_filter = filt;
693  m_textures[tex].m_wrap = wrap;
694  uint type = m_textures[tex].m_type;
695  glBindTexture(type, tex);
696  uint mag_filt = filt;
697  if (filt == GL_LINEAR_MIPMAP_LINEAR)
698  {
699  mag_filt = GL_LINEAR;
700 #ifdef GL_GENERATE_MIPMAP_HINT_SGIS
701  glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
702 #endif
703 #ifdef GL_GENERATE_MIPMAP_SGIS
704  glTexParameteri(type, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
705 #endif
706  }
707  glTexParameteri(type, GL_TEXTURE_MIN_FILTER, filt);
708  glTexParameteri(type, GL_TEXTURE_MAG_FILTER, mag_filt);
709  glTexParameteri(type, GL_TEXTURE_WRAP_S, wrap);
710  glTexParameteri(type, GL_TEXTURE_WRAP_T, wrap);
711  doneCurrent();
712 }
713 
715 {
716  if (!(m_exts_used & kGLMultiTex))
717  return;
718 
719  makeCurrent();
720  if (m_active_tex != active_tex)
721  {
722  m_glActiveTexture(active_tex);
723  m_active_tex = active_tex;
724  }
725  doneCurrent();
726 }
727 
728 void MythRenderOpenGL::StoreBicubicWeights(float x, float *dst)
729 {
730  float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
731  float w1 = ((( 3 * x - 6) * x + 0) * x + 4) / 6;
732  float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
733  float w3 = ((( 1 * x + 0) * x + 0) * x + 0) / 6;
734  *dst++ = 1 + x - w1 / (w0 + w1);
735  *dst++ = 1 - x + w3 / (w2 + w3);
736  *dst++ = w0 + w1;
737  *dst++ = 0;
738 }
739 
741 {
742  if (tex && !m_textures.contains(tex))
743  return;
744 
745  makeCurrent();
746  int type = tex ? m_textures[tex].m_type : tex_type;
747  if (type != m_active_tex_type)
748  {
749 #ifndef USING_OPENGLES
750  if (m_active_tex_type)
751  glDisable(m_active_tex_type);
752  glEnable(type);
753 #endif
755  }
756  doneCurrent();
757 }
758 
760 {
761  if (!m_active_tex_type)
762  return;
763  makeCurrent();
764 #ifndef USING_OPENGLES
765  glDisable(m_active_tex_type);
766 #endif
767  m_active_tex_type = 0;
768  doneCurrent();
769 }
770 
772 {
773  if (!m_textures.contains(tex))
774  return;
775 
776  makeCurrent();
777 
778  GLuint gltex = tex;
779  glDeleteTextures(1, &gltex);
780  if (m_textures[tex].m_data)
781  delete m_textures[tex].m_data;
782  if (m_textures[tex].m_pbo)
783  m_glDeleteBuffers(1, &(m_textures[tex].m_pbo));
784  if (m_textures[tex].m_vbo)
785  m_glDeleteBuffers(1, &(m_textures[tex].m_vbo));
786  m_textures.remove(tex);
787 
788  Flush(true);
789  doneCurrent();
790 }
791 
793 {
794  if (!(m_exts_used & kGLExtFBufObj))
795  return false;
796 
797  if (!m_textures.contains(tex))
798  return false;
799 
800  QSize size = m_textures[tex].m_size;
801  GLuint glfb;
802 
803  makeCurrent();
804  glCheck();
805 
806  EnableTextures(tex);
807  QRect tmp_viewport = m_viewport;
808  glViewport(0, 0, size.width(), size.height());
809  m_glGenFramebuffers(1, &glfb);
811  glBindTexture(m_textures[tex].m_type, tex);
812  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
813  size.width(), size.height(), 0,
814  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, nullptr);
816  m_textures[tex].m_type, tex, 0);
817 
818  GLenum status;
821  glViewport(tmp_viewport.left(), tmp_viewport.top(),
822  tmp_viewport.width(), tmp_viewport.height());
823 
824  bool success = false;
825  switch (status)
826  {
828  LOG(VB_PLAYBACK, LOG_INFO, LOC +
829  QString("Created frame buffer object (%1x%2).")
830  .arg(size.width()).arg(size.height()));
831  success = true;
832  break;
834  LOG(VB_PLAYBACK, LOG_INFO, LOC +
835  "Frame buffer incomplete_ATTACHMENT");
836  break;
838  LOG(VB_PLAYBACK, LOG_INFO, LOC +
839  "Frame buffer incomplete_MISSING_ATTACHMENT");
840  break;
842  LOG(VB_PLAYBACK, LOG_INFO, LOC +
843  "Frame buffer incomplete_DUPLICATE_ATTACHMENT");
844  break;
846  LOG(VB_PLAYBACK, LOG_INFO, LOC +
847  "Frame buffer incomplete_DIMENSIONS");
848  break;
850  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer incomplete_FORMATS");
851  break;
853  LOG(VB_PLAYBACK, LOG_INFO, LOC +
854  "Frame buffer incomplete_DRAW_BUFFER");
855  break;
857  LOG(VB_PLAYBACK, LOG_INFO, LOC +
858  "Frame buffer incomplete_READ_BUFFER");
859  break;
861  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer unsupported.");
862  break;
863  default:
864  LOG(VB_PLAYBACK, LOG_INFO, LOC +
865  QString("Unknown frame buffer error %1.").arg(status));
866  }
867 
868  if (success)
869  m_framebuffers.push_back(glfb);
870  else
871  m_glDeleteFramebuffers(1, &glfb);
872 
873  Flush(true);
874  glCheck();
875  doneCurrent();
876  fb = glfb;
877  return success;
878 }
879 
881 {
882  if (!m_framebuffers.contains(fb))
883  return;
884 
885  makeCurrent();
886  QVector<GLuint>::iterator it;
887  for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
888  {
889  if (*it == fb)
890  {
891  m_glDeleteFramebuffers(1, &(*it));
892  m_framebuffers.erase(it);
893  break;
894  }
895  }
896 
897  Flush(true);
898  doneCurrent();
899 }
900 
902 {
903  if (fb && !m_framebuffers.contains(fb))
904  return;
905 
906  if (fb == (uint)m_active_fb)
907  return;
908 
909  makeCurrent();
911  doneCurrent();
912  m_active_fb = fb;
913 }
914 
916 {
917  makeCurrent();
918  glClear(GL_COLOR_BUFFER_BIT);
919  doneCurrent();
920 }
921 
922 void MythRenderOpenGL::DrawBitmap(uint tex, uint target, const QRect *src,
923  const QRect *dst, uint prog, int alpha,
924  int red, int green, int blue)
925 {
926  if (!tex || !m_textures.contains(tex))
927  return;
928 
929  if (target && !m_framebuffers.contains(target))
930  target = 0;
931 
932  makeCurrent();
933  BindFramebuffer(target);
934  DrawBitmapPriv(tex, src, dst, prog, alpha, red, green, blue);
935  doneCurrent();
936 }
937 
938 void MythRenderOpenGL::DrawBitmap(uint *textures, uint texture_count,
939  uint target, const QRectF *src,
940  const QRectF *dst, uint prog)
941 {
942  if (!textures || !texture_count)
943  return;
944 
945  if (target && !m_framebuffers.contains(target))
946  target = 0;
947 
948  makeCurrent();
949  BindFramebuffer(target);
950  DrawBitmapPriv(textures, texture_count, src, dst, prog);
951  doneCurrent();
952 }
953 
954 void MythRenderOpenGL::DrawRect(const QRect &area, const QBrush &fillBrush,
955  const QPen &linePen, int alpha)
956 {
957  makeCurrent();
958  BindFramebuffer(0);
959  DrawRectPriv(area, fillBrush, linePen, alpha);
960  doneCurrent();
961 }
962 
963 void MythRenderOpenGL::DrawRoundRect(const QRect &area, int cornerRadius,
964  const QBrush &fillBrush,
965  const QPen &linePen, int alpha)
966 {
967  makeCurrent();
968  BindFramebuffer(0);
969  DrawRoundRectPriv(area, cornerRadius, fillBrush, linePen, alpha);
970  doneCurrent();
971 }
972 
974 {
975  SetBlend(false);
976  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
977  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
978  glDisable(GL_DEPTH_TEST);
979  glDepthMask(GL_FALSE);
980  glDisable(GL_CULL_FACE);
981  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
982  glClear(GL_COLOR_BUFFER_BIT);
983  Flush(true);
984 }
985 
987 {
988  m_extensions = (reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
989 
991  GetProcAddress("glActiveTexture");
993  GetProcAddress("glMapBuffer");
995  GetProcAddress("glBindBuffer");
997  GetProcAddress("glGenBuffers");
999  GetProcAddress("glBufferData");
1001  GetProcAddress("glUnmapBuffer");
1003  GetProcAddress("glDeleteBuffers");
1005  GetProcAddress("glGenFramebuffers");
1007  GetProcAddress("glBindFramebuffer");
1009  GetProcAddress("glFramebufferTexture2D");
1011  GetProcAddress("glCheckFramebufferStatus");
1013  GetProcAddress("glDeleteFramebuffers");
1015  GetProcAddress("glGenFencesNV");
1017  GetProcAddress("glDeleteFencesNV");
1019  GetProcAddress("glSetFenceNV");
1021  GetProcAddress("glFinishFenceNV");
1023  GetProcAddress("glGenFencesAPPLE");
1025  GetProcAddress("glDeleteFencesAPPLE");
1027  GetProcAddress("glSetFenceAPPLE");
1029  GetProcAddress("glFinishFenceAPPLE");
1030 }
1031 
1032 void* MythRenderOpenGL::GetProcAddress(const QString &proc) const
1033 {
1034  // TODO FIXME - this should really return a void(*) not void*
1035  static const QString exts[4] = { "", "ARB", "EXT", "OES" };
1036  void *result;
1037  for (int i = 0; i < 4; i++)
1038  {
1039 #ifdef USING_OPENGLES
1040  result = reinterpret_cast<void*>(
1041  QLibrary::resolve("libGLESv2", (proc + exts[i]).toLatin1().data()));
1042  if (result)
1043  break;
1044 #else
1045  result = reinterpret_cast<void*>(getProcAddress(qPrintable(proc + exts[i])));
1046  if (result)
1047  break;
1048 #endif
1049  }
1050  if (result == nullptr)
1051  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1052  QString("Extension not found: %1").arg(proc));
1053 
1054  return result;
1055 }
1056 
1058 {
1059  static bool multitexture = true;
1060  static bool vertexarrays = true;
1061  static bool framebuffers = true;
1062  static bool pixelbuffers = true;
1063  static bool vertexbuffers = true;
1064  static bool fences = true;
1065  static bool ycbcrtextures = true;
1066  static bool mipmapping = true;
1067  static bool rgba16 = true;
1068  static bool check = true;
1069 
1070  if (check)
1071  {
1072  check = false;
1073  multitexture = !getenv("OPENGL_NOMULTITEX");
1074  vertexarrays = !getenv("OPENGL_NOVERTARRAY");
1075  framebuffers = !getenv("OPENGL_NOFBO");
1076  pixelbuffers = !getenv("OPENGL_NOPBO");
1077  vertexbuffers = !getenv("OPENGL_NOVBO");
1078  fences = !getenv("OPENGL_NOFENCE");
1079  ycbcrtextures = !getenv("OPENGL_NOYCBCR");
1080  mipmapping = !getenv("OPENGL_NOMIPMAP");
1081  rgba16 = !getenv("OPENGL_NORGBA16");
1082  if (!multitexture)
1083  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling multi-texturing.");
1084  if (!vertexarrays)
1085  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Arrays.");
1086  if (!framebuffers)
1087  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Framebuffer Objects.");
1088  if (!pixelbuffers)
1089  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Pixel Buffer Objects.");
1090  if (!vertexbuffers)
1091  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Buffer Objects.");
1092  if (!fences)
1093  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling fences.");
1094  if (!ycbcrtextures)
1095  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling YCbCr textures.");
1096  if (!mipmapping)
1097  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling mipmapping.");
1098  if (!rgba16)
1099  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling RGBA16 textures");
1100  }
1101 
1102  GLint maxtexsz = 0;
1103  GLint maxunits = 0;
1104  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsz);
1105  glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxunits);
1106  m_max_units = maxunits;
1107  m_max_tex_size = (maxtexsz) ? maxtexsz : 512;
1108 
1109  m_extensions = (const char*) glGetString(GL_EXTENSIONS);
1110  bool rects;
1112  if (rects)
1114 
1115  // GL 1.1
1116  if (rgba16)
1118 
1119  if (m_extensions.contains("GL_ARB_multitexture") &&
1120  m_glActiveTexture && multitexture)
1121  {
1123  if (m_max_units < 3)
1124  {
1125  LOG(VB_GENERAL, LOG_ERR, LOC +
1126  "Insufficient texture units for advanced OpenGL features.");
1127  }
1128  }
1129  else
1130  {
1131  LOG(VB_GENERAL, LOG_ERR, LOC + "Multi-texturing not supported. Certain "
1132  "OpenGL features will not work");
1133  }
1134 
1135  if (m_extensions.contains("GL_EXT_vertex_array") && vertexarrays)
1136  {
1138  }
1139  else
1140  {
1141  LOG(VB_GENERAL, LOG_ERR, LOC +
1142  "GL_EXT_vertex_array extension not supported. This may not work");
1143  }
1144 
1145  if (m_extensions.contains("GL_EXT_framebuffer_object") &&
1148  m_glCheckFramebufferStatus && framebuffers)
1150 
1151  bool buffer_procs = m_glMapBuffer && m_glBindBuffer &&
1154 
1155  if(m_extensions.contains("GL_ARB_pixel_buffer_object")
1156  && buffer_procs && pixelbuffers)
1158 
1159  if (m_extensions.contains("GL_ARB_vertex_buffer_object")
1160  && buffer_procs && vertexbuffers)
1162 
1163  if(m_extensions.contains("GL_NV_fence") &&
1165  m_glSetFenceNV && m_glFinishFenceNV && fences)
1167 
1168  if(m_extensions.contains("GL_APPLE_fence") &&
1172 
1173  if (m_extensions.contains("GL_MESA_ycbcr_texture") && ycbcrtextures)
1175 
1176  if (m_extensions.contains("GL_APPLE_ycbcr_422") && ycbcrtextures)
1178 
1179  if (m_extensions.contains("GL_SGIS_generate_mipmap") && mipmapping)
1181 
1182  static bool debugged = false;
1183  if (!debugged)
1184  {
1185  debugged = true;
1186  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL vendor : %1")
1187  .arg((const char*) glGetString(GL_VENDOR)));
1188  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL renderer: %1")
1189  .arg((const char*) glGetString(GL_RENDERER)));
1190  LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL version : %1")
1191  .arg((const char*) glGetString(GL_VERSION)));
1192  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture size: %1 x %2")
1193  .arg(m_max_tex_size).arg(m_max_tex_size));
1194  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture units: %1")
1195  .arg(m_max_units));
1196  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Direct rendering: %1")
1197  .arg(IsDirectRendering() ? "Yes" : "No"));
1198  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Extensions Supported: %1")
1199  .arg(m_exts_supported, 0, 16));
1200  }
1201 
1203 
1204  if (m_exts_used & kGLExtPBufObj)
1205  {
1206  LOG(VB_GENERAL, LOG_INFO, LOC + "PixelBufferObject support available");
1207  }
1208 
1209  return true;
1210 }
1211 
1213 {
1214  m_fence = 0;
1215 
1216  m_lock_level = 0;
1217 
1218  m_extensions = QString();
1221  m_max_tex_size = 0;
1222  m_max_units = 0;
1223  m_default_texture_type = GL_TEXTURE_2D;
1224 
1225  m_viewport = QRect();
1226  m_active_tex = 0;
1227  m_active_tex_type = 0;
1228  m_active_fb = 0;
1229  m_blend = false;
1230  m_background = 0x00000000;
1231  m_flushEnabled = true;
1232 }
1233 
1235 {
1236  m_extensions = QString();
1237 
1238  m_glActiveTexture = nullptr;
1239  m_glMapBuffer = nullptr;
1240  m_glBindBuffer = nullptr;
1241  m_glGenBuffers = nullptr;
1242  m_glBufferData = nullptr;
1243  m_glUnmapBuffer = nullptr;
1244  m_glDeleteBuffers = nullptr;
1245  m_glGenFramebuffers = nullptr;
1246  m_glBindFramebuffer = nullptr;
1247  m_glFramebufferTexture2D = nullptr;
1248  m_glCheckFramebufferStatus = nullptr;
1249  m_glDeleteFramebuffers = nullptr;
1250  m_glGenFencesNV = nullptr;
1251  m_glDeleteFencesNV = nullptr;
1252  m_glSetFenceNV = nullptr;
1253  m_glFinishFenceNV = nullptr;
1254  m_glGenFencesAPPLE = nullptr;
1255  m_glDeleteFencesAPPLE = nullptr;
1256  m_glSetFenceAPPLE = nullptr;
1257  m_glFinishFenceAPPLE = nullptr;
1258 }
1259 
1261 {
1262  if (!(m_exts_used & kGLExtPBufObj))
1263  return 0;
1264 
1265  if (!m_textures.contains(tex))
1266  return 0;
1267 
1269  if (glCheck())
1270  {
1271  // looks like we dont support PBOs so dont bother doing the rest
1272  // and stop using it in the future
1273  LOG(VB_GENERAL, LOG_INFO, LOC + "Pixel Buffer Objects unusable, disabling");
1276  return 0;
1277  }
1278  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
1279  m_textures[tex].m_size.width(),
1280  m_textures[tex].m_size.height(), 0,
1281  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, nullptr);
1282 
1283  GLuint tmp_pbo;
1284  m_glGenBuffers(1, &tmp_pbo);
1286 
1287  Flush(true);
1288  return tmp_pbo;
1289 }
1290 
1292 {
1293  if (!(m_exts_used & kGLExtVBO))
1294  return 0;
1295 
1296  GLuint tmp_vbo;
1297  m_glGenBuffers(1, &tmp_vbo);
1298  return tmp_vbo;
1299 }
1300 
1302 {
1303  LOG(VB_GENERAL, LOG_INFO, LOC + "Deleting OpenGL Resources");
1304  DeleteTextures();
1306  Flush(true);
1307 
1308  if (m_fence)
1309  {
1312  else if(m_exts_supported & kGLNVFence)
1314  m_fence = 0;
1315  }
1316 
1317  Flush(false);
1318 
1319  ExpireVertices();
1320  ExpireVBOS();
1321 
1322  if (m_cachedVertices.size())
1323  {
1324  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired vertices")
1325  .arg(m_cachedVertices.size()));
1326  }
1327 
1328  if (m_cachedVBOS.size())
1329  {
1330  LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired VBOs")
1331  .arg(m_cachedVertices.size()));
1332  }
1333 }
1334 
1336 {
1337  QHash<GLuint, MythGLTexture>::iterator it;
1338  for (it = m_textures.begin(); it !=m_textures.end(); ++it)
1339  {
1340  glDeleteTextures(1, &(it.key()));
1341  if (it.value().m_data)
1342  delete it.value().m_data;
1343  if (it.value().m_pbo)
1344  m_glDeleteBuffers(1, &(it.value().m_pbo));
1345  }
1346  m_textures.clear();
1347  Flush(true);
1348 }
1349 
1351 {
1352  QVector<GLuint>::iterator it;
1353  for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
1354  m_glDeleteFramebuffers(1, &(*(it)));
1355  m_framebuffers.clear();
1356  Flush(true);
1357 }
1358 
1360  const QRect *dst)
1361 {
1362  if (!m_textures.contains(tex))
1363  return false;
1364 
1365  GLfloat *data = m_textures[tex].m_vertex_data;
1366  QSize size = m_textures[tex].m_size;
1367 
1368  int width = min(src->width(), size.width());
1369  int height = min(src->height(), size.height());
1370 
1371  data[0 + TEX_OFFSET] = src->left();
1372  data[1 + TEX_OFFSET] = src->top() + height;
1373 
1374  data[6 + TEX_OFFSET] = src->left() + width;
1375  data[7 + TEX_OFFSET] = src->top();
1376 
1377  if (!IsRectTexture(m_textures[tex].m_type))
1378  {
1379  data[0 + TEX_OFFSET] /= (float)size.width();
1380  data[6 + TEX_OFFSET] /= (float)size.width();
1381  data[1 + TEX_OFFSET] /= (float)size.height();
1382  data[7 + TEX_OFFSET] /= (float)size.height();
1383  }
1384 
1385  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1386  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1387  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1388  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1389 
1390  data[2] = data[0] = dst->left();
1391  data[5] = data[1] = dst->top();
1392  data[4] = data[6] = dst->left() + min(width, dst->width());
1393  data[3] = data[7] = dst->top() + min(height, dst->height());
1394 
1395  return true;
1396 }
1397 
1398 bool MythRenderOpenGL::UpdateTextureVertices(uint tex, const QRectF *src,
1399  const QRectF *dst)
1400 {
1401  if (!m_textures.contains(tex))
1402  return false;
1403 
1404  GLfloat *data = m_textures[tex].m_vertex_data;
1405 
1406  data[0 + TEX_OFFSET] = src->left();
1407  data[1 + TEX_OFFSET] = src->top() + src->height();
1408 
1409  data[6 + TEX_OFFSET] = src->left() + src->width();
1410  data[7 + TEX_OFFSET] = src->top();
1411 
1412  if (!IsRectTexture(m_textures[tex].m_type))
1413  {
1414  data[0 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
1415  data[6 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
1416  data[1 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
1417  data[7 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
1418  }
1419 
1420  data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
1421  data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
1422  data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
1423  data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
1424 
1425  data[2] = data[0] = dst->left();
1426  data[5] = data[1] = dst->top();
1427  data[4] = data[6] = dst->left() + dst->width();
1428  data[3] = data[7] = dst->top() + dst->height();
1429 
1430  return true;
1431 }
1432 
1433 GLfloat* MythRenderOpenGL::GetCachedVertices(GLuint type, const QRect &area)
1434 {
1435  uint64_t ref = ((uint64_t)area.left() & 0xfff) +
1436  (((uint64_t)area.top() & 0xfff) << 12) +
1437  (((uint64_t)area.width() & 0xfff) << 24) +
1438  (((uint64_t)area.height() & 0xfff) << 36) +
1439  (((uint64_t)type & 0xfff) << 48);
1440 
1441  if (m_cachedVertices.contains(ref))
1442  {
1443  m_vertexExpiry.removeOne(ref);
1444  m_vertexExpiry.append(ref);
1445  return m_cachedVertices[ref];
1446  }
1447 
1448  GLfloat *vertices = new GLfloat[8];
1449 
1450  vertices[2] = vertices[0] = area.left();
1451  vertices[5] = vertices[1] = area.top();
1452  vertices[4] = vertices[6] = area.left() + area.width();
1453  vertices[3] = vertices[7] = area.top() + area.height();
1454 
1455  if (type == GL_LINE_LOOP)
1456  {
1457  vertices[7] = vertices[1];
1458  vertices[5] = vertices[3];
1459  }
1460 
1461  m_cachedVertices.insert(ref, vertices);
1462  m_vertexExpiry.append(ref);
1464 
1465  return vertices;
1466 }
1467 
1469 {
1470  while ((uint)m_vertexExpiry.size() > max)
1471  {
1472  uint64_t ref = m_vertexExpiry.first();
1473  m_vertexExpiry.removeFirst();
1474  GLfloat *vertices = nullptr;
1475  if (m_cachedVertices.contains(ref))
1476  vertices = m_cachedVertices.value(ref);
1477  m_cachedVertices.remove(ref);
1478  delete [] vertices;
1479  }
1480 }
1481 
1482 void MythRenderOpenGL::GetCachedVBO(GLuint type, const QRect &area)
1483 {
1484  uint64_t ref = ((uint64_t)area.left() & 0xfff) +
1485  (((uint64_t)area.top() & 0xfff) << 12) +
1486  (((uint64_t)area.width() & 0xfff) << 24) +
1487  (((uint64_t)area.height() & 0xfff) << 36) +
1488  (((uint64_t)type & 0xfff) << 48);
1489 
1490  if (m_cachedVBOS.contains(ref))
1491  {
1492  m_vboExpiry.removeOne(ref);
1493  m_vboExpiry.append(ref);
1494  }
1495  else
1496  {
1497  GLfloat *vertices = GetCachedVertices(type, area);
1498  GLuint vbo = CreateVBO();
1499  m_cachedVBOS.insert(ref, vbo);
1500  m_vboExpiry.append(ref);
1501 
1503  if (m_exts_used & kGLExtPBufObj)
1504  {
1506  void* target = m_glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
1507  if (target)
1508  memcpy(target, vertices, kTextureOffset);
1510  }
1511  else
1512  {
1514  }
1516  return;
1517  }
1518 
1520 }
1521 
1523 {
1524  while ((uint)m_vboExpiry.size() > max)
1525  {
1526  uint64_t ref = m_vboExpiry.first();
1527  m_vboExpiry.removeFirst();
1528  if (m_cachedVBOS.contains(ref))
1529  {
1530  GLuint vbo = m_cachedVBOS.value(ref);
1531  m_glDeleteBuffers(1, &vbo);
1532  m_cachedVBOS.remove(ref);
1533  }
1534  }
1535 }
1536 
1538 {
1539  if (!m_textures.contains(tex))
1540  return false;
1541 
1542  QSize size = m_textures[tex].m_size;
1543  uint tmp_size = GetBufferSize(size, m_textures[tex].m_data_fmt,
1544  m_textures[tex].m_data_type);
1545 
1546  if (!tmp_size)
1547  return false;
1548 
1549  unsigned char *scratch = new unsigned char[tmp_size];
1550 
1551  if (!scratch)
1552  return false;
1553 
1554  memset(scratch, 0, tmp_size);
1555 
1556  glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
1557  size.width(), size.height(), 0, m_textures[tex].m_data_fmt,
1558  m_textures[tex].m_data_type, scratch);
1559  delete [] scratch;
1560 
1561  if (glCheck())
1562  {
1563  LOG(VB_GENERAL, LOG_ERR, LOC + QString("glTexImage size %1 failed")
1564  .arg(tmp_size));
1565  return false;
1566  }
1567 
1568  return true;
1569 }
1570 
1572 {
1573  uint bytes;
1574  uint bpp;
1575 
1576  if (fmt ==GL_RGBA)
1577  {
1578  bpp = 4;
1579  }
1580  else if (fmt == GL_RGB)
1581  {
1582  bpp = 3;
1583  }
1584  else if (fmt == GL_YCBCR_MESA || fmt == GL_YCBCR_422_APPLE)
1585  {
1586  bpp = 2;
1587  }
1588  else if (fmt == GL_LUMINANCE || fmt == GL_ALPHA)
1589  {
1590  bpp = 1;
1591  }
1592  else
1593  {
1594  bpp =0;
1595  }
1596 
1597  switch (type)
1598  {
1599  case GL_UNSIGNED_BYTE:
1600  bytes = sizeof(GLubyte);
1601  break;
1602 #ifdef GL_UNSIGNED_SHORT_8_8_MESA
1604  bytes = sizeof(GLushort);
1605  break;
1606 #endif
1607  case GL_FLOAT:
1608  bytes = sizeof(GLfloat);
1609  break;
1610  default:
1611  bytes = 0;
1612  }
1613 
1614  if (!bpp || !bytes || size.width() < 1 || size.height() < 1)
1615  return 0;
1616 
1617  return size.width() * size.height() * bpp * bytes;
1618 }
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:41
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:340
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:340
void EnableTextures(uint type, uint tex_type=0)
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
#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:340
void(APIENTRY * MYTH_GLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer)