MythTV  0.26-pre
mythrender_opengl.cpp
Go to the documentation of this file.
00001 #include <algorithm>
00002 using namespace std;
00003 
00004 #include "mythlogging.h"
00005 #include "mythrender_opengl.h"
00006 #include "mythxdisplay.h"
00007 
00008 #define LOC QString("OpenGL: ")
00009 
00010 #include "mythrender_opengl2.h"
00011 #ifdef USING_OPENGLES
00012 #include "mythrender_opengl2es.h"
00013 #else
00014 #include "mythrender_opengl1.h"
00015 #endif
00016 
00017 #ifdef USING_X11
00018 #include "util-nvctrl.h"
00019 #endif
00020 
00021 static const GLuint kTextureOffset = 8 * sizeof(GLfloat);
00022 
00023 static inline int __glCheck__(const QString &loc, const char* fileName, int n)
00024 {
00025     int error = glGetError();
00026     if (error)
00027     {
00028         LOG(VB_GENERAL, LOG_ERR, QString("%1: %2 @ %3, %4")
00029             .arg(loc).arg(error).arg(fileName).arg(n));
00030     }
00031     return error;
00032 }
00033 
00034 #define MAX_VERTEX_CACHE 500
00035 #define glCheck() __glCheck__(LOC, __FILE__, __LINE__)
00036 
00037 OpenGLLocker::OpenGLLocker(MythRenderOpenGL *render) : m_render(render)
00038 {
00039     if (m_render)
00040         m_render->makeCurrent();
00041 }
00042 
00043 OpenGLLocker::~OpenGLLocker()
00044 {
00045     if (m_render)
00046         m_render->doneCurrent();
00047 }
00048 
00049 MythRenderOpenGL* MythRenderOpenGL::Create(const QString &painter,
00050                                            QPaintDevice* device)
00051 {
00052     QGLFormat format;
00053     format.setDepth(false);
00054 
00055     bool setswapinterval = false;
00056     int synctovblank = -1;
00057 
00058 #ifdef USING_X11
00059     synctovblank = CheckNVOpenGLSyncToVBlank();
00060 #endif
00061 
00062     if (synctovblank < 0)
00063     {
00064         LOG(VB_GENERAL, LOG_WARNING, LOC + "Could not determine whether Sync "
00065                                            "to VBlank is enabled.");
00066     }
00067     else if (synctovblank == 0)
00068     {
00069         // currently only Linux NVidia is supported and there is no way of
00070         // forcing sync to vblank after the app has started. util-nvctrl will
00071         // warn the user and offer advice on settings.
00072     }
00073     else
00074     {
00075         LOG(VB_GENERAL, LOG_INFO, LOC + "Sync to VBlank is enabled (good!)");
00076     }
00077 
00078 #if defined(Q_WS_MAC)
00079     LOG(VB_GENERAL, LOG_INFO, LOC + "Forcing swap interval for OS X.");
00080     setswapinterval = true;
00081 #endif
00082 
00083     if (setswapinterval)
00084         format.setSwapInterval(1);
00085 
00086 #ifdef USING_OPENGLES
00087     if (device)
00088         return new MythRenderOpenGL2ES(format, device);
00089     return new MythRenderOpenGL2ES(format);
00090 #else
00091     if (painter.contains("opengl2"))
00092     {
00093         if (device)
00094             return new MythRenderOpenGL2(format, device);
00095         return new MythRenderOpenGL2(format);
00096     }
00097     if (device)
00098         return new MythRenderOpenGL1(format, device);
00099     return new MythRenderOpenGL1(format);
00100 
00101 #endif
00102 }
00103 
00104 MythRenderOpenGL::MythRenderOpenGL(const QGLFormat& format, QPaintDevice* device,
00105                                    RenderType type)
00106   : QGLContext(format, device), MythRender(type)
00107 {
00108 }
00109 
00110 MythRenderOpenGL::MythRenderOpenGL(const QGLFormat& format, RenderType type)
00111   : QGLContext(format), MythRender(type)
00112 {
00113 }
00114 
00115 MythRenderOpenGL::~MythRenderOpenGL()
00116 {
00117     delete m_lock;
00118 }
00119 
00120 void MythRenderOpenGL::Init(void)
00121 {
00122     OpenGLLocker locker(this);
00123     InitProcs();
00124     Init2DState();
00125     InitFeatures();
00126 
00127     LOG(VB_GENERAL, LOG_INFO, LOC + "Initialised MythRenderOpenGL");
00128 }
00129 
00130 bool MythRenderOpenGL::IsRecommendedRenderer(void)
00131 {
00132     bool recommended = true;
00133     OpenGLLocker locker(this);
00134     QString renderer = (const char*) glGetString(GL_RENDERER);
00135     if (!(this->format().directRendering()))
00136     {
00137         LOG(VB_GENERAL, LOG_WARNING, LOC +
00138             "OpenGL is using software rendering.");
00139         recommended = false;
00140     }
00141     else if (renderer.contains("Software Rasterizer", Qt::CaseInsensitive))
00142     {
00143         LOG(VB_GENERAL, LOG_WARNING, LOC +
00144             "OpenGL is using software rasterizer.");
00145         recommended = false;
00146     }
00147     else if (renderer.contains("softpipe", Qt::CaseInsensitive))
00148     {
00149         LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL seems to be using software "
00150             "fallback. Please check your OpenGL driver installation, "
00151             "configuration, and device permissions.");
00152         recommended = false;
00153     }
00154     return recommended;
00155 }
00156 
00157 void MythRenderOpenGL::makeCurrent()
00158 {
00159     m_lock->lock();
00160     if (this != MythRenderOpenGL::currentContext())
00161         QGLContext::makeCurrent();
00162     m_lock_level++;
00163 }
00164 
00165 void MythRenderOpenGL::doneCurrent()
00166 {
00167     m_lock_level--;
00168     if (m_lock_level == 0)
00169         QGLContext::doneCurrent();
00170     if (m_lock_level < 0)
00171         LOG(VB_GENERAL, LOG_ERR, LOC + "Mis-matched calls to makeCurrent()");
00172     m_lock->unlock();
00173 }
00174 
00175 void MythRenderOpenGL::Release(void)
00176 {
00177 #if !defined(Q_WS_WIN)
00178     while (m_lock_level > 0)
00179         doneCurrent();
00180 #endif
00181 }
00182 
00183 void MythRenderOpenGL::MoveResizeWindow(const QRect &rect)
00184 {
00185     QWidget *parent = (QWidget*)this->device();
00186     if (parent)
00187         parent->setGeometry(rect);
00188 }
00189 
00190 void MythRenderOpenGL::SetViewPort(const QRect &rect, bool viewportonly)
00191 {
00192     if (rect == m_viewport)
00193         return;
00194     makeCurrent();
00195     m_viewport = rect;
00196     glViewport(m_viewport.left(), m_viewport.top(),
00197                m_viewport.width(), m_viewport.height());
00198     if (!viewportonly)
00199         SetMatrixView();
00200     doneCurrent();
00201 }
00202 
00203 void MythRenderOpenGL::Flush(bool use_fence)
00204 {
00205     makeCurrent();
00206 
00207     if ((m_exts_used & kGLAppleFence) &&
00208         (m_fence && use_fence))
00209     {
00210         m_glSetFenceAPPLE(m_fence);
00211         m_glFinishFenceAPPLE(m_fence);
00212     }
00213     else if ((m_exts_used & kGLNVFence) &&
00214              (m_fence && use_fence))
00215     {
00216         m_glSetFenceNV(m_fence, GL_ALL_COMPLETED_NV);
00217         m_glFinishFenceNV(m_fence);
00218     }
00219     else
00220     {
00221         glFlush();
00222     }
00223 
00224     doneCurrent();
00225 }
00226 
00227 void MythRenderOpenGL::SetBlend(bool enable)
00228 {
00229     makeCurrent();
00230     if (enable && !m_blend)
00231         glEnable(GL_BLEND);
00232     else if (!enable && m_blend)
00233         glDisable(GL_BLEND);
00234     m_blend = enable;
00235     doneCurrent();
00236 }
00237 
00238 void MythRenderOpenGL::SetBackground(int r, int g, int b, int a)
00239 {
00240     uint32_t tmp = (r << 24) + (g << 16) + (b << 8) + a;
00241     if (tmp == m_background)
00242         return;
00243 
00244     m_background = tmp;
00245     makeCurrent();
00246     glClearColor(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
00247     doneCurrent();
00248 }
00249 
00250 void MythRenderOpenGL::SetFence(void)
00251 {
00252     makeCurrent();
00253     if (m_exts_used & kGLAppleFence)
00254     {
00255         m_glGenFencesAPPLE(1, &m_fence);
00256         if (m_fence)
00257             LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_APPLE_fence");
00258     }
00259     else if (m_exts_used & kGLNVFence)
00260     {
00261         m_glGenFencesNV(1, &m_fence);
00262         if (m_fence)
00263             LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using GL_NV_fence");
00264     }
00265     doneCurrent();
00266 }
00267 
00268 void* MythRenderOpenGL::GetTextureBuffer(uint tex, bool create_buffer)
00269 {
00270     if (!m_textures.contains(tex))
00271         return NULL;
00272 
00273     makeCurrent(); // associated doneCurrent() in UpdateTexture
00274 
00275     EnableTextures(tex);
00276     glBindTexture(m_textures[tex].m_type, tex);
00277 
00278     if (!create_buffer)
00279         return NULL;
00280 
00281     if (m_textures[tex].m_pbo)
00282     {
00283         m_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_textures[tex].m_pbo);
00284         m_glBufferData(GL_PIXEL_UNPACK_BUFFER,
00285                              m_textures[tex].m_data_size, NULL, GL_STREAM_DRAW);
00286         return m_glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
00287     }
00288 
00289     if (m_textures[tex].m_data)
00290         return m_textures[tex].m_data;
00291 
00292     unsigned char *scratch = new unsigned char[m_textures[tex].m_data_size];
00293     if (scratch)
00294     {
00295         memset(scratch, 0, m_textures[tex].m_data_size);
00296         m_textures[tex].m_data = scratch;
00297     }
00298     return scratch;
00299 }
00300 
00301 void MythRenderOpenGL::UpdateTexture(uint tex, void *buf)
00302 {
00303     // N.B. GetTextureBuffer must be called first
00304     if (!m_textures.contains(tex))
00305         return;
00306 
00307     QSize size = m_textures[tex].m_act_size;
00308 
00309     if (m_textures[tex].m_pbo)
00310     {
00311         m_glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
00312         glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
00313                         size.height(), m_textures[tex].m_data_fmt,
00314                         m_textures[tex].m_data_type, 0);
00315         m_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
00316     }
00317     else
00318     {
00319         glTexSubImage2D(m_textures[tex].m_type, 0, 0, 0, size.width(),
00320                         size.height(), m_textures[tex].m_data_fmt,
00321                         m_textures[tex].m_data_type, buf);
00322     }
00323 
00324     doneCurrent();
00325 }
00326 
00327 int MythRenderOpenGL::GetTextureType(bool &rect)
00328 {
00329     static bool rects = true;
00330     static bool check = true;
00331     if (check)
00332     {
00333         check = false;
00334         rects = !getenv("OPENGL_NORECT");
00335         if (!rects)
00336             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling NPOT textures.");
00337     }
00338 
00339     int ret = GL_TEXTURE_2D;
00340 
00341     if (m_extensions.contains("GL_NV_texture_rectangle") && rects)
00342         ret = GL_TEXTURE_RECTANGLE_NV;
00343     else if (m_extensions.contains("GL_ARB_texture_rectangle") && rects)
00344         ret = GL_TEXTURE_RECTANGLE_ARB;
00345     else if (m_extensions.contains("GL_EXT_texture_rectangle") && rects)
00346         ret = GL_TEXTURE_RECTANGLE_EXT;
00347 
00348     rect = (ret != GL_TEXTURE_2D);
00349     return ret;
00350 }
00351 
00352 bool MythRenderOpenGL::IsRectTexture(uint type)
00353 {
00354     if (type == GL_TEXTURE_RECTANGLE_NV || type == GL_TEXTURE_RECTANGLE_ARB ||
00355         type == GL_TEXTURE_RECTANGLE_EXT)
00356         return true;
00357     return false;
00358 }
00359 
00360 uint MythRenderOpenGL::CreateTexture(QSize act_size, bool use_pbo,
00361                                      uint type, uint data_type,
00362                                      uint data_fmt, uint internal_fmt,
00363                                      uint filter, uint wrap)
00364 {
00365     if (!type)
00366         type = m_default_texture_type;
00367 
00368     QSize tot_size = GetTextureSize(type, act_size);
00369 
00370     makeCurrent();
00371 
00372     EnableTextures(0, type);
00373 
00374     GLuint tex;
00375     glGenTextures(1, &tex);
00376     glBindTexture(type, tex);
00377 
00378     if (tex)
00379     {
00380         MythGLTexture texture;
00381         texture.m_type         = type;
00382         texture.m_data_type    = data_type;
00383         texture.m_data_fmt     = data_fmt;
00384         texture.m_internal_fmt = internal_fmt;
00385         texture.m_size         = tot_size;
00386         texture.m_act_size     = act_size;
00387         texture.m_data_size    = GetBufferSize(act_size, data_fmt, data_type);
00388         m_textures.insert(tex, texture);
00389 
00390         if (ClearTexture(tex) && m_textures[tex].m_data_size)
00391         {
00392             SetTextureFilters(tex, filter, wrap);
00393             if (use_pbo)
00394                 m_textures[tex].m_pbo = CreatePBO(tex);
00395             if (m_exts_used & kGLExtVBO)
00396                 m_textures[tex].m_vbo = CreateVBO();
00397         }
00398         else
00399         {
00400             DeleteTexture(tex);
00401             tex = 0;
00402         }
00403     }
00404 
00405     Flush(true);
00406     doneCurrent();
00407 
00408     return tex;
00409 }
00410 
00411 QSize MythRenderOpenGL::GetTextureSize(uint type, const QSize &size)
00412 {
00413     if (IsRectTexture(type))
00414         return size;
00415 
00416     int w = 64;
00417     int h = 64;
00418 
00419     while (w < size.width())
00420     {
00421         w *= 2;
00422     }
00423 
00424     while (h < size.height())
00425     {
00426         h *= 2;
00427     }
00428 
00429     return QSize(w, h);
00430 }
00431 
00432 QSize MythRenderOpenGL::GetTextureSize(uint tex)
00433 {
00434     if (!m_textures.contains(tex))
00435         return QSize();
00436     return m_textures[tex].m_size;
00437 }
00438 
00439 int MythRenderOpenGL::GetTextureDataSize(uint tex)
00440 {
00441     if (!m_textures.contains(tex))
00442         return 0;
00443     return m_textures[tex].m_data_size;
00444 }
00445 
00446 void MythRenderOpenGL::SetTextureFilters(uint tex, uint filt, uint wrap)
00447 {
00448     if (!m_textures.contains(tex))
00449         return;
00450 
00451     bool mipmaps = (m_exts_used & kGLMipMaps) &&
00452                    !IsRectTexture(m_textures[tex].m_type);
00453     if (filt == GL_LINEAR_MIPMAP_LINEAR && !mipmaps)
00454         filt = GL_LINEAR;
00455 
00456     makeCurrent();
00457     EnableTextures(tex);
00458     m_textures[tex].m_filter = filt;
00459     m_textures[tex].m_wrap   = wrap;
00460     uint type = m_textures[tex].m_type;
00461     glBindTexture(type, tex);
00462     uint mag_filt = filt;
00463     if (filt == GL_LINEAR_MIPMAP_LINEAR)
00464     {
00465         mag_filt = GL_LINEAR;
00466         glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
00467         glTexParameteri(type, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00468     }
00469     glTexParameteri(type, GL_TEXTURE_MIN_FILTER, filt);
00470     glTexParameteri(type, GL_TEXTURE_MAG_FILTER, mag_filt);
00471     glTexParameteri(type, GL_TEXTURE_WRAP_S, wrap);
00472     if (type != GL_TEXTURE_1D)
00473         glTexParameteri(type, GL_TEXTURE_WRAP_T, wrap);
00474     doneCurrent();
00475 }
00476 
00477 void MythRenderOpenGL::ActiveTexture(int active_tex)
00478 {
00479     if (!(m_exts_used & kGLMultiTex))
00480         return;
00481 
00482     makeCurrent();
00483     if (m_active_tex != active_tex)
00484     {
00485         m_glActiveTexture(active_tex);
00486         m_active_tex = active_tex;
00487     }
00488     doneCurrent();
00489 }
00490 
00491 void MythRenderOpenGL::StoreBicubicWeights(float x, float *dst)
00492 {
00493     float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
00494     float w1 = ((( 3 * x - 6) * x + 0) * x + 4) / 6;
00495     float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
00496     float w3 = ((( 1 * x + 0) * x + 0) * x + 0) / 6;
00497     *dst++ = 1 + x - w1 / (w0 + w1);
00498     *dst++ = 1 - x + w3 / (w2 + w3);
00499     *dst++ = w0 + w1;
00500     *dst++ = 0;
00501 }
00502 
00503 void MythRenderOpenGL::EnableTextures(uint tex, uint tex_type)
00504 {
00505     if (tex && !m_textures.contains(tex))
00506         return;
00507 
00508     makeCurrent();
00509     int type = tex ? m_textures[tex].m_type : tex_type;
00510     if (type != m_active_tex_type)
00511     {
00512         if (m_active_tex_type)
00513             glDisable(m_active_tex_type);
00514         glEnable(type);
00515         m_active_tex_type = type;
00516     }
00517     doneCurrent();
00518 }
00519 
00520 void MythRenderOpenGL::DisableTextures(void)
00521 {
00522     if (!m_active_tex_type)
00523         return;
00524     makeCurrent();
00525     glDisable(m_active_tex_type);
00526     m_active_tex_type = 0;
00527     doneCurrent();
00528 }
00529 
00530 void MythRenderOpenGL::DeleteTexture(uint tex)
00531 {
00532     if (!m_textures.contains(tex))
00533         return;
00534 
00535     makeCurrent();
00536 
00537     GLuint gltex = tex;
00538     glDeleteTextures(1, &gltex);
00539     if (m_textures[tex].m_data)
00540         delete m_textures[tex].m_data;
00541     if (m_textures[tex].m_pbo)
00542         m_glDeleteBuffers(1, &(m_textures[tex].m_pbo));
00543     if (m_textures[tex].m_vbo)
00544         m_glDeleteBuffers(1, &(m_textures[tex].m_vbo));
00545     m_textures.remove(tex);
00546 
00547     Flush(true);
00548     doneCurrent();
00549 }
00550 
00551 bool MythRenderOpenGL::CreateFrameBuffer(uint &fb, uint tex)
00552 {
00553     if (!(m_exts_used & kGLExtFBufObj))
00554         return false;
00555 
00556     if (!m_textures.contains(tex))
00557         return false;
00558 
00559     QSize size = m_textures[tex].m_size;
00560     GLuint glfb;
00561 
00562     makeCurrent();
00563     glCheck();
00564 
00565     EnableTextures(tex);
00566     QRect tmp_viewport = m_viewport;
00567     glViewport(0, 0, size.width(), size.height());
00568     m_glGenFramebuffers(1, &glfb);
00569     m_glBindFramebuffer(GL_FRAMEBUFFER, glfb);
00570     glBindTexture(m_textures[tex].m_type, tex);
00571     glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
00572                  (GLint) size.width(), (GLint) size.height(), 0,
00573                  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, NULL);
00574     m_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
00575                              m_textures[tex].m_type, tex, 0);
00576 
00577     GLenum status;
00578     status = m_glCheckFramebufferStatus(GL_FRAMEBUFFER);
00579     m_glBindFramebuffer(GL_FRAMEBUFFER, 0);
00580     glViewport(tmp_viewport.left(), tmp_viewport.top(),
00581                tmp_viewport.width(), tmp_viewport.height());
00582 
00583     bool success = false;
00584     switch (status)
00585     {
00586         case GL_FRAMEBUFFER_COMPLETE:
00587             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00588                 QString("Created frame buffer object (%1x%2).")
00589                     .arg(size.width()).arg(size.height()));
00590             success = true;
00591             break;
00592         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
00593             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00594                 "Frame buffer incomplete_ATTACHMENT");
00595             break;
00596         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
00597             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00598                 "Frame buffer incomplete_MISSING_ATTACHMENT");
00599             break;
00600         case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:
00601             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00602                 "Frame buffer incomplete_DUPLICATE_ATTACHMENT");
00603             break;
00604         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
00605             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00606                 "Frame buffer incomplete_DIMENSIONS");
00607             break;
00608         case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
00609             LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer incomplete_FORMATS");
00610             break;
00611         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
00612             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00613                 "Frame buffer incomplete_DRAW_BUFFER");
00614             break;
00615         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
00616             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00617                 "Frame buffer incomplete_READ_BUFFER");
00618             break;
00619         case GL_FRAMEBUFFER_UNSUPPORTED:
00620             LOG(VB_PLAYBACK, LOG_INFO, LOC + "Frame buffer unsupported.");
00621             break;
00622         default:
00623             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00624                 QString("Unknown frame buffer error %1.").arg(status));
00625     }
00626 
00627     if (success)
00628         m_framebuffers.push_back(glfb);
00629     else
00630         m_glDeleteFramebuffers(1, &glfb);
00631 
00632     Flush(true);
00633     glCheck();
00634     doneCurrent();
00635     fb = glfb;
00636     return success;
00637 }
00638 
00639 void MythRenderOpenGL::DeleteFrameBuffer(uint fb)
00640 {
00641     if (!m_framebuffers.contains(fb))
00642         return;
00643 
00644     makeCurrent();
00645     QVector<GLuint>::iterator it;
00646     for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
00647     {
00648         if (*it == fb)
00649         {
00650             m_glDeleteFramebuffers(1, &(*it));
00651             m_framebuffers.erase(it);
00652             break;
00653         }
00654     }
00655 
00656     Flush(true);
00657     doneCurrent();
00658 }
00659 
00660 void MythRenderOpenGL::BindFramebuffer(uint fb)
00661 {
00662     if (fb && !m_framebuffers.contains(fb))
00663         return;
00664 
00665     if (fb == (uint)m_active_fb)
00666         return;
00667 
00668     makeCurrent();
00669     m_glBindFramebuffer(GL_FRAMEBUFFER, fb);
00670     doneCurrent();
00671     m_active_fb = fb;
00672 }
00673 
00674 void MythRenderOpenGL::ClearFramebuffer(void)
00675 {
00676     makeCurrent();
00677     glClear(GL_COLOR_BUFFER_BIT);
00678     doneCurrent();
00679 }
00680 
00681 void MythRenderOpenGL::DrawBitmap(uint tex, uint target, const QRect *src,
00682                                   const QRect *dst, uint prog, int alpha,
00683                                   int red, int green, int blue)
00684 {
00685     if (!tex || !m_textures.contains(tex))
00686         return;
00687 
00688     if (target && !m_framebuffers.contains(target))
00689         target = 0;
00690 
00691     makeCurrent();
00692     BindFramebuffer(target);
00693     DrawBitmapPriv(tex, src, dst, prog, alpha, red, green, blue);
00694     doneCurrent();
00695 }
00696 
00697 void MythRenderOpenGL::DrawBitmap(uint *textures, uint texture_count,
00698                                   uint target, const QRectF *src,
00699                                   const QRectF *dst, uint prog)
00700 {
00701     if (!textures || !texture_count)
00702         return;
00703 
00704     if (target && !m_framebuffers.contains(target))
00705         target = 0;
00706 
00707     makeCurrent();
00708     BindFramebuffer(target);
00709     DrawBitmapPriv(textures, texture_count, src, dst, prog);
00710     doneCurrent();
00711 }
00712 
00713 void MythRenderOpenGL::DrawRect(const QRect &area, const QBrush &fillBrush,
00714                                 const QPen &linePen, int alpha)
00715 {
00716     makeCurrent();
00717     BindFramebuffer(0);
00718     DrawRectPriv(area, fillBrush, linePen, alpha);
00719     doneCurrent();
00720 }
00721 
00722 void MythRenderOpenGL::DrawRoundRect(const QRect &area, int cornerRadius,
00723                                      const QBrush &fillBrush,
00724                                      const QPen &linePen, int alpha)
00725 {
00726     makeCurrent();
00727     BindFramebuffer(0);
00728     DrawRoundRectPriv(area, cornerRadius, fillBrush, linePen, alpha);
00729     doneCurrent();
00730 }
00731 
00732 void MythRenderOpenGL::Init2DState(void)
00733 {
00734     SetBlend(false);
00735     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00736     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00737     glDisable(GL_DEPTH_TEST);
00738     glDepthMask(GL_FALSE);
00739     glDisable(GL_CULL_FACE);
00740     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00741     glClear(GL_COLOR_BUFFER_BIT);
00742     Flush(true);
00743 }
00744 
00745 void MythRenderOpenGL::InitProcs(void)
00746 {
00747     m_extensions = (reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
00748 
00749     m_glTexImage1D = (MYTH_GLTEXIMAGE1DPROC)
00750         GetProcAddress("glTexImage1D");
00751     m_glActiveTexture = (MYTH_GLACTIVETEXTUREPROC)
00752         GetProcAddress("glActiveTexture");
00753     m_glMapBuffer = (MYTH_GLMAPBUFFERPROC)
00754         GetProcAddress("glMapBuffer");
00755     m_glBindBuffer = (MYTH_GLBINDBUFFERPROC)
00756         GetProcAddress("glBindBuffer");
00757     m_glGenBuffers = (MYTH_GLGENBUFFERSPROC)
00758         GetProcAddress("glGenBuffers");
00759     m_glBufferData = (MYTH_GLBUFFERDATAPROC)
00760         GetProcAddress("glBufferData");
00761     m_glUnmapBuffer = (MYTH_GLUNMAPBUFFERPROC)
00762         GetProcAddress("glUnmapBuffer");
00763     m_glDeleteBuffers = (MYTH_GLDELETEBUFFERSPROC)
00764         GetProcAddress("glDeleteBuffers");
00765     m_glGenFramebuffers = (MYTH_GLGENFRAMEBUFFERSPROC)
00766         GetProcAddress("glGenFramebuffers");
00767     m_glBindFramebuffer = (MYTH_GLBINDFRAMEBUFFERPROC)
00768         GetProcAddress("glBindFramebuffer");
00769     m_glFramebufferTexture2D = (MYTH_GLFRAMEBUFFERTEXTURE2DPROC)
00770         GetProcAddress("glFramebufferTexture2D");
00771     m_glCheckFramebufferStatus = (MYTH_GLCHECKFRAMEBUFFERSTATUSPROC)
00772         GetProcAddress("glCheckFramebufferStatus");
00773     m_glDeleteFramebuffers = (MYTH_GLDELETEFRAMEBUFFERSPROC)
00774         GetProcAddress("glDeleteFramebuffers");
00775     m_glGenFencesNV = (MYTH_GLGENFENCESNVPROC)
00776         GetProcAddress("glGenFencesNV");
00777     m_glDeleteFencesNV = (MYTH_GLDELETEFENCESNVPROC)
00778         GetProcAddress("glDeleteFencesNV");
00779     m_glSetFenceNV = (MYTH_GLSETFENCENVPROC)
00780         GetProcAddress("glSetFenceNV");
00781     m_glFinishFenceNV = (MYTH_GLFINISHFENCENVPROC)
00782         GetProcAddress("glFinishFenceNV");
00783     m_glGenFencesAPPLE = (MYTH_GLGENFENCESAPPLEPROC)
00784         GetProcAddress("glGenFencesAPPLE");
00785     m_glDeleteFencesAPPLE = (MYTH_GLDELETEFENCESAPPLEPROC)
00786         GetProcAddress("glDeleteFencesAPPLE");
00787     m_glSetFenceAPPLE = (MYTH_GLSETFENCEAPPLEPROC)
00788         GetProcAddress("glSetFenceAPPLE");
00789     m_glFinishFenceAPPLE = (MYTH_GLFINISHFENCEAPPLEPROC)
00790         GetProcAddress("glFinishFenceAPPLE");
00791 }
00792 
00793 void* MythRenderOpenGL::GetProcAddress(const QString &proc) const
00794 {
00795     static const QString exts[4] = { "", "ARB", "EXT", "OES" };
00796     void *result;
00797     for (int i = 0; i < 4; i++)
00798     {
00799         result = getProcAddress(proc + exts[i]);
00800         if (result)
00801             break;
00802     }
00803     if (result == NULL)
00804         LOG(VB_GENERAL, LOG_DEBUG, LOC +
00805             QString("Extension not found: %1").arg(proc));
00806 
00807     return result;
00808 }
00809 
00810 bool MythRenderOpenGL::InitFeatures(void)
00811 {
00812     static bool multitexture  = true;
00813     static bool vertexarrays  = true;
00814     static bool framebuffers  = true;
00815     static bool pixelbuffers  = true;
00816     static bool vertexbuffers = true;
00817     static bool fences        = true;
00818     static bool ycbcrtextures = true;
00819     static bool mipmapping    = true;
00820     static bool check         = true;
00821 
00822     if (check)
00823     {
00824         check = false;
00825         multitexture  = !getenv("OPENGL_NOMULTITEX");
00826         vertexarrays  = !getenv("OPENGL_NOVERTARRAY");
00827         framebuffers  = !getenv("OPENGL_NOFBO");
00828         pixelbuffers  = !getenv("OPENGL_NOPBO");
00829         vertexbuffers = !getenv("OPENGL_NOVBO");
00830         fences        = !getenv("OPENGL_NOFENCE");
00831         ycbcrtextures = !getenv("OPENGL_NOYCBCR");
00832         mipmapping    = !getenv("OPENGL_NOMIPMAP");
00833         if (!multitexture)
00834             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling multi-texturing.");
00835         if (!vertexarrays)
00836             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Arrays.");
00837         if (!framebuffers)
00838             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Framebuffer Objects.");
00839         if (!pixelbuffers)
00840             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Pixel Buffer Objects.");
00841         if (!vertexbuffers)
00842             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling Vertex Buffer Objects.");
00843         if (!fences)
00844             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling fences.");
00845         if (!ycbcrtextures)
00846             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling YCbCr textures.");
00847         if (!mipmapping)
00848             LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling mipmapping.");
00849     }
00850 
00851     GLint maxtexsz = 0;
00852     GLint maxunits = 0;
00853     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsz);
00854     glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxunits);
00855     m_max_units = maxunits;
00856     m_max_tex_size = (maxtexsz) ? maxtexsz : 512;
00857 
00858     m_extensions = (const char*) glGetString(GL_EXTENSIONS);
00859     bool rects;
00860     m_default_texture_type = GetTextureType(rects);
00861     if (rects)
00862         m_exts_supported += kGLExtRect;
00863 
00864     if (m_extensions.contains("GL_ARB_multitexture") &&
00865         m_glActiveTexture && multitexture)
00866     {
00867         m_exts_supported += kGLMultiTex;
00868         if (m_max_units < 3)
00869         {
00870             LOG(VB_GENERAL, LOG_ERR, LOC +
00871                 "Insufficient texture units for advanced OpenGL features.");
00872         }
00873     }
00874     else
00875     {
00876         LOG(VB_GENERAL, LOG_ERR, LOC + "Multi-texturing not supported. Certain "
00877                                        "OpenGL features will not work");
00878     }
00879 
00880     if (m_extensions.contains("GL_EXT_vertex_array") && vertexarrays)
00881     {
00882         m_exts_supported += kGLVertexArray;
00883     }
00884     else
00885     {
00886         LOG(VB_GENERAL, LOG_ERR, LOC +
00887             "GL_EXT_vertex_array extension not supported. This may not work");
00888     }
00889 
00890     if (m_extensions.contains("GL_EXT_framebuffer_object") &&
00891         m_glGenFramebuffers        && m_glBindFramebuffer &&
00892         m_glFramebufferTexture2D   && m_glDeleteFramebuffers &&
00893         m_glCheckFramebufferStatus && framebuffers)
00894         m_exts_supported += kGLExtFBufObj;
00895 
00896     bool buffer_procs = m_glMapBuffer  && m_glBindBuffer &&
00897                         m_glGenBuffers && m_glDeleteBuffers &&
00898                         m_glBufferData && m_glUnmapBuffer;
00899 
00900     if(m_extensions.contains("GL_ARB_pixel_buffer_object")
00901        && buffer_procs && pixelbuffers)
00902         m_exts_supported += kGLExtPBufObj;
00903 
00904     if (m_extensions.contains("GL_ARB_vertex_buffer_object")
00905         && buffer_procs && vertexbuffers)
00906         m_exts_supported += kGLExtVBO;
00907 
00908     if(m_extensions.contains("GL_NV_fence") &&
00909         m_glGenFencesNV && m_glDeleteFencesNV &&
00910         m_glSetFenceNV  && m_glFinishFenceNV && fences)
00911         m_exts_supported += kGLNVFence;
00912 
00913     if(m_extensions.contains("GL_APPLE_fence") &&
00914         m_glGenFencesAPPLE && m_glDeleteFencesAPPLE &&
00915         m_glSetFenceAPPLE  && m_glFinishFenceAPPLE && fences)
00916         m_exts_supported += kGLAppleFence;
00917 
00918     if (m_extensions.contains("GL_MESA_ycbcr_texture") && ycbcrtextures)
00919         m_exts_supported += kGLMesaYCbCr;
00920 
00921     if (m_extensions.contains("GL_APPLE_ycbcr_422") && ycbcrtextures)
00922         m_exts_supported += kGLAppleYCbCr;
00923 
00924     if (m_extensions.contains("GL_SGIS_generate_mipmap") && mipmapping)
00925         m_exts_supported += kGLMipMaps;
00926 
00927     static bool debugged = false;
00928     if (!debugged)
00929     {
00930         debugged = true;
00931         LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL vendor  : %1")
00932                 .arg((const char*) glGetString(GL_VENDOR)));
00933         LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL renderer: %1")
00934                 .arg((const char*) glGetString(GL_RENDERER)));
00935         LOG(VB_GENERAL, LOG_INFO, LOC + QString("OpenGL version : %1")
00936                 .arg((const char*) glGetString(GL_VERSION)));
00937         LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture size: %1 x %2")
00938                 .arg(m_max_tex_size).arg(m_max_tex_size));
00939         LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max texture units: %1")
00940                 .arg(m_max_units));
00941         LOG(VB_GENERAL, LOG_INFO, LOC + QString("Direct rendering: %1")
00942                 .arg((this->format().directRendering()) ? "Yes" : "No"));
00943     }
00944 
00945     m_exts_used = m_exts_supported;
00946 
00947     if (m_exts_used & kGLExtPBufObj)
00948     {
00949         LOG(VB_GENERAL, LOG_INFO, LOC + "PixelBufferObject support available");
00950     }
00951 
00952     return true;
00953 }
00954 
00955 void MythRenderOpenGL::ResetVars(void)
00956 {
00957     m_fence           = 0;
00958 
00959     m_lock            = new QMutex(QMutex::Recursive);
00960     m_lock_level      = 0;
00961 
00962     m_extensions      = QString();
00963     m_exts_supported  = kGLFeatNone;
00964     m_exts_used       = kGLFeatNone;
00965     m_max_tex_size    = 0;
00966     m_max_units       = 0;
00967     m_default_texture_type = GL_TEXTURE_2D;
00968 
00969     m_viewport        = QRect();
00970     m_active_tex      = 0;
00971     m_active_tex_type = 0;
00972     m_active_fb       = 0;
00973     m_blend           = false;
00974     m_background      = 0x00000000;
00975 }
00976 
00977 void MythRenderOpenGL::ResetProcs(void)
00978 {
00979     m_extensions = QString();
00980 
00981     m_glTexImage1D = NULL;
00982     m_glActiveTexture = NULL;
00983     m_glMapBuffer = NULL;
00984     m_glBindBuffer = NULL;
00985     m_glGenBuffers = NULL;
00986     m_glBufferData = NULL;
00987     m_glUnmapBuffer = NULL;
00988     m_glDeleteBuffers = NULL;
00989     m_glGenFramebuffers = NULL;
00990     m_glBindFramebuffer = NULL;
00991     m_glFramebufferTexture2D = NULL;
00992     m_glCheckFramebufferStatus = NULL;
00993     m_glDeleteFramebuffers = NULL;
00994     m_glGenFencesNV = NULL;
00995     m_glDeleteFencesNV = NULL;
00996     m_glSetFenceNV = NULL;
00997     m_glFinishFenceNV = NULL;
00998     m_glGenFencesAPPLE = NULL;
00999     m_glDeleteFencesAPPLE = NULL;
01000     m_glSetFenceAPPLE = NULL;
01001     m_glFinishFenceAPPLE = NULL;
01002 }
01003 
01004 uint MythRenderOpenGL::CreatePBO(uint tex)
01005 {
01006     if (!(m_exts_used & kGLExtPBufObj))
01007         return 0;
01008 
01009     if (!m_textures.contains(tex))
01010         return 0;
01011 
01012     m_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
01013     glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
01014                  m_textures[tex].m_size.width(),
01015                  m_textures[tex].m_size.height(), 0,
01016                  m_textures[tex].m_data_fmt, m_textures[tex].m_data_type, NULL);
01017 
01018     GLuint tmp_pbo;
01019     m_glGenBuffers(1, &tmp_pbo);
01020     m_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
01021 
01022     Flush(true);
01023     return tmp_pbo;
01024 }
01025 
01026 uint MythRenderOpenGL::CreateVBO(void)
01027 {
01028     if (!(m_exts_used & kGLExtVBO))
01029         return 0;
01030 
01031     GLuint tmp_vbo;
01032     m_glGenBuffers(1, &tmp_vbo);
01033     return tmp_vbo;
01034 }
01035 
01036 void MythRenderOpenGL::DeleteOpenGLResources(void)
01037 {
01038     LOG(VB_GENERAL, LOG_INFO, LOC + "Deleting OpenGL Resources");
01039     DeleteTextures();
01040     DeleteFrameBuffers();
01041     Flush(true);
01042 
01043     if (m_fence)
01044     {
01045         if (m_exts_supported & kGLAppleFence)
01046             m_glDeleteFencesAPPLE(1, &m_fence);
01047         else if(m_exts_supported & kGLNVFence)
01048             m_glDeleteFencesNV(1, &m_fence);
01049         m_fence = 0;
01050     }
01051 
01052     Flush(false);
01053 
01054     ExpireVertices();
01055     ExpireVBOS();
01056 
01057     if (m_cachedVertices.size())
01058     {
01059         LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired vertices")
01060             .arg(m_cachedVertices.size()));
01061     }
01062 
01063     if (m_cachedVBOS.size())
01064     {
01065         LOG(VB_GENERAL, LOG_ERR, LOC + QString(" %1 unexpired VBOs")
01066             .arg(m_cachedVertices.size()));
01067     }
01068 }
01069 
01070 void MythRenderOpenGL::DeleteTextures(void)
01071 {
01072     QHash<GLuint, MythGLTexture>::iterator it;
01073     for (it = m_textures.begin(); it !=m_textures.end(); ++it)
01074     {
01075         glDeleteTextures(1, &(it.key()));
01076         if (it.value().m_data)
01077             delete it.value().m_data;
01078         if (it.value().m_pbo)
01079             m_glDeleteBuffers(1, &(it.value().m_pbo));
01080     }
01081     m_textures.clear();
01082     Flush(true);
01083 }
01084 
01085 void MythRenderOpenGL::DeleteFrameBuffers(void)
01086 {
01087     QVector<GLuint>::iterator it;
01088     for (it = m_framebuffers.begin(); it != m_framebuffers.end(); ++it)
01089         m_glDeleteFramebuffers(1, &(*(it)));
01090     m_framebuffers.clear();
01091     Flush(true);
01092 }
01093 
01094 bool MythRenderOpenGL::UpdateTextureVertices(uint tex, const QRect *src,
01095                                              const QRect *dst)
01096 {
01097     if (!m_textures.contains(tex))
01098         return false;
01099 
01100     GLfloat *data = m_textures[tex].m_vertex_data;
01101     QSize    size = m_textures[tex].m_size;
01102 
01103     int width  = min(src->width(),  size.width());
01104     int height = min(src->height(), size.height());
01105 
01106     data[0 + TEX_OFFSET] = src->left();
01107     data[1 + TEX_OFFSET] = src->top() + height;
01108 
01109     data[6 + TEX_OFFSET] = src->left() + width;
01110     data[7 + TEX_OFFSET] = src->top();
01111 
01112     if (!IsRectTexture(m_textures[tex].m_type))
01113     {
01114         data[0 + TEX_OFFSET] /= (float)size.width();
01115         data[6 + TEX_OFFSET] /= (float)size.width();
01116         data[1 + TEX_OFFSET] /= (float)size.height();
01117         data[7 + TEX_OFFSET] /= (float)size.height();
01118     }
01119 
01120     data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
01121     data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
01122     data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
01123     data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
01124 
01125     data[2] = data[0] = dst->left();
01126     data[5] = data[1] = dst->top();
01127     data[4] = data[6] = dst->left() + min(width, dst->width());
01128     data[3] = data[7] = dst->top()  + min(height, dst->height());
01129 
01130     return true;
01131 }
01132 
01133 bool MythRenderOpenGL::UpdateTextureVertices(uint tex, const QRectF *src,
01134                                              const QRectF *dst)
01135 {
01136     if (!m_textures.contains(tex))
01137         return false;
01138 
01139     GLfloat *data = m_textures[tex].m_vertex_data;
01140 
01141     data[0 + TEX_OFFSET] = src->left();
01142     data[1 + TEX_OFFSET] = src->top() + src->height();
01143 
01144     data[6 + TEX_OFFSET] = src->left() + src->width();
01145     data[7 + TEX_OFFSET] = src->top();
01146 
01147     if (!IsRectTexture(m_textures[tex].m_type))
01148     {
01149         data[0 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
01150         data[6 + TEX_OFFSET] /= (float)m_textures[tex].m_size.width();
01151         data[1 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
01152         data[7 + TEX_OFFSET] /= (float)m_textures[tex].m_size.height();
01153     }
01154 
01155     data[2 + TEX_OFFSET] = data[0 + TEX_OFFSET];
01156     data[3 + TEX_OFFSET] = data[7 + TEX_OFFSET];
01157     data[4 + TEX_OFFSET] = data[6 + TEX_OFFSET];
01158     data[5 + TEX_OFFSET] = data[1 + TEX_OFFSET];
01159 
01160     data[2] = data[0] = dst->left();
01161     data[5] = data[1] = dst->top();
01162     data[4] = data[6] = dst->left() + dst->width();
01163     data[3] = data[7] = dst->top() + dst->height();
01164 
01165     return true;
01166 }
01167 
01168 GLfloat* MythRenderOpenGL::GetCachedVertices(GLuint type, const QRect &area)
01169 {
01170     uint64_t ref = ((uint64_t)area.left() & 0xfff) +
01171                   (((uint64_t)area.top() & 0xfff) << 12) +
01172                   (((uint64_t)area.width() & 0xfff) << 24) +
01173                   (((uint64_t)area.height() & 0xfff) << 36) +
01174                   (((uint64_t)type & 0xfff) << 48);
01175 
01176     if (m_cachedVertices.contains(ref))
01177     {
01178         m_vertexExpiry.removeOne(ref);
01179         m_vertexExpiry.append(ref);
01180         return m_cachedVertices[ref];
01181     }
01182 
01183     GLfloat *vertices = new GLfloat[8];
01184 
01185     vertices[2] = vertices[0] = area.left();
01186     vertices[5] = vertices[1] = area.top();
01187     vertices[4] = vertices[6] = area.left() + area.width();
01188     vertices[3] = vertices[7] = area.top() + area.height();
01189 
01190     if (type == GL_LINE_LOOP)
01191     {
01192         vertices[7] = vertices[1];
01193         vertices[5] = vertices[3];
01194     }
01195 
01196     m_cachedVertices.insert(ref, vertices);
01197     m_vertexExpiry.append(ref);
01198     ExpireVertices(MAX_VERTEX_CACHE);
01199 
01200     return vertices;
01201 }
01202 
01203 void MythRenderOpenGL::ExpireVertices(uint max)
01204 {
01205     while ((uint)m_vertexExpiry.size() > max)
01206     {
01207         uint64_t ref = m_vertexExpiry.first();
01208         m_vertexExpiry.removeFirst();
01209         GLfloat *vertices = NULL;
01210         if (m_cachedVertices.contains(ref))
01211             vertices = m_cachedVertices.value(ref);
01212         m_cachedVertices.remove(ref);
01213         delete [] vertices;
01214     }
01215 }
01216 
01217 void MythRenderOpenGL::GetCachedVBO(GLuint type, const QRect &area)
01218 {
01219     uint64_t ref = ((uint64_t)area.left() & 0xfff) +
01220                   (((uint64_t)area.top() & 0xfff) << 12) +
01221                   (((uint64_t)area.width() & 0xfff) << 24) +
01222                   (((uint64_t)area.height() & 0xfff) << 36) +
01223                   (((uint64_t)type & 0xfff) << 48);
01224 
01225     if (m_cachedVBOS.contains(ref))
01226     {
01227         m_vboExpiry.removeOne(ref);
01228         m_vboExpiry.append(ref);
01229     }
01230     else
01231     {
01232         GLfloat *vertices = GetCachedVertices(type, area);
01233         GLuint vbo = CreateVBO();
01234         m_cachedVBOS.insert(ref, vbo);
01235         m_vboExpiry.append(ref);
01236 
01237         m_glBindBuffer(GL_ARRAY_BUFFER, vbo);
01238         m_glBufferData(GL_ARRAY_BUFFER, kTextureOffset, NULL, GL_STREAM_DRAW);
01239         void* target = m_glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
01240         if (target)
01241             memcpy(target, vertices, kTextureOffset);
01242         m_glUnmapBuffer(GL_ARRAY_BUFFER);
01243 
01244         ExpireVBOS(MAX_VERTEX_CACHE);
01245         return;
01246     }
01247 
01248     m_glBindBuffer(GL_ARRAY_BUFFER, m_cachedVBOS.value(ref));
01249 }
01250 
01251 void MythRenderOpenGL::ExpireVBOS(uint max)
01252 {
01253     while ((uint)m_vboExpiry.size() > max)
01254     {
01255         uint64_t ref = m_vboExpiry.first();
01256         m_vboExpiry.removeFirst();
01257         if (m_cachedVBOS.contains(ref))
01258         {
01259             GLuint vbo = m_cachedVBOS.value(ref);
01260             m_glDeleteBuffers(1, &vbo);
01261             m_cachedVBOS.remove(ref);
01262         }
01263     }
01264 }
01265 
01266 bool MythRenderOpenGL::ClearTexture(uint tex)
01267 {
01268     if (!m_textures.contains(tex))
01269         return false;
01270 
01271     QSize size = m_textures[tex].m_size;
01272     uint tmp_size = GetBufferSize(size, m_textures[tex].m_data_fmt,
01273                                   m_textures[tex].m_data_type);
01274 
01275     if (!tmp_size)
01276         return false;
01277 
01278     unsigned char *scratch = new unsigned char[tmp_size];
01279 
01280     if (!scratch)
01281         return false;
01282 
01283     memset(scratch, 0, tmp_size);
01284 
01285     if ((m_textures[tex].m_type == GL_TEXTURE_1D) && m_glTexImage1D)
01286     {
01287         m_glTexImage1D(m_textures[tex].m_type, 0,
01288                        m_textures[tex].m_internal_fmt,
01289                        size.width(), 0, m_textures[tex].m_data_fmt,
01290                        m_textures[tex].m_data_type, scratch);
01291     }
01292     else
01293     {
01294         glTexImage2D(m_textures[tex].m_type, 0, m_textures[tex].m_internal_fmt,
01295                      size.width(), size.height(), 0, m_textures[tex].m_data_fmt,
01296                      m_textures[tex].m_data_type, scratch);
01297     }
01298     delete [] scratch;
01299 
01300     return true;
01301 }
01302 
01303 uint MythRenderOpenGL::GetBufferSize(QSize size, uint fmt, uint type)
01304 {
01305     uint bytes;
01306     uint bpp;
01307 
01308     if (fmt == GL_BGRA || fmt ==GL_RGBA)
01309     {
01310         bpp = 4;
01311     }
01312     else if (fmt == GL_YCBCR_MESA || fmt == GL_YCBCR_422_APPLE ||
01313              fmt == MYTHTV_UYVY)
01314     {
01315         bpp = 2;
01316     }
01317     else
01318     {
01319         bpp =0;
01320     }
01321 
01322     switch (type)
01323     {
01324         case GL_UNSIGNED_BYTE:
01325             bytes = sizeof(GLubyte);
01326             break;
01327         case GL_UNSIGNED_SHORT_8_8_MESA:
01328             bytes = sizeof(GLushort);
01329             break;
01330         case GL_FLOAT:
01331             bytes = sizeof(GLfloat);
01332             break;
01333         default:
01334             bytes = 0;
01335     }
01336 
01337     if (!bpp || !bytes || size.width() < 1 || size.height() < 1)
01338         return 0;
01339 
01340     return size.width() * size.height() * bpp * bytes;
01341 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends