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
00070
00071
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();
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
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 }