|
MythTV
0.26-pre
|
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 }
1.7.6.1