00001
00002 #include "config.h"
00003
00004
00005 #include <QCoreApplication>
00006 #include <QPainter>
00007 #include <QGLWidget>
00008
00009
00010 #include "mythlogging.h"
00011
00012
00013 #include "mythrender_opengl.h"
00014
00015
00016 #include "mythpainter_ogl.h"
00017
00018 using namespace std;
00019
00020 MythOpenGLPainter::MythOpenGLPainter(MythRenderOpenGL *render,
00021 QGLWidget *parent) :
00022 MythPainter(), realParent(parent), realRender(render),
00023 target(0), swapControl(true)
00024 {
00025 if (realRender)
00026 LOG(VB_GENERAL, LOG_INFO,
00027 "OpenGL painter using existing OpenGL context.");
00028 if (realParent)
00029 LOG(VB_GENERAL, LOG_INFO, "OpenGL painter using existing QGLWidget.");
00030 }
00031
00032 MythOpenGLPainter::~MythOpenGLPainter()
00033 {
00034 ExpireImages(0);
00035 FreeResources();
00036 }
00037
00038 void MythOpenGLPainter::FreeResources(void)
00039 {
00040 ClearCache();
00041 DeleteTextures();
00042 }
00043
00044 void MythOpenGLPainter::DeleteTextures(void)
00045 {
00046 if (!realRender || m_textureDeleteList.empty())
00047 return;
00048
00049 QMutexLocker locker(&m_textureDeleteLock);
00050 while (!m_textureDeleteList.empty())
00051 {
00052 uint tex = m_textureDeleteList.front();
00053 m_HardwareCacheSize -= realRender->GetTextureDataSize(tex);
00054 realRender->DeleteTexture(tex);
00055 m_textureDeleteList.pop_front();
00056 }
00057 realRender->Flush(true);
00058 }
00059
00060 void MythOpenGLPainter::ClearCache(void)
00061 {
00062 LOG(VB_GENERAL, LOG_INFO, "Clearing OpenGL painter cache.");
00063
00064 QMutexLocker locker(&m_textureDeleteLock);
00065 QMapIterator<MythImage *, unsigned int> it(m_ImageIntMap);
00066 while (it.hasNext())
00067 {
00068 it.next();
00069 m_textureDeleteList.push_back(m_ImageIntMap[it.key()]);
00070 m_ImageExpireList.remove(it.key());
00071 }
00072 m_ImageIntMap.clear();
00073 }
00074
00075 void MythOpenGLPainter::Begin(QPaintDevice *parent)
00076 {
00077 MythPainter::Begin(parent);
00078
00079 if (!realParent && parent)
00080 realParent = dynamic_cast<QGLWidget *>(parent);
00081
00082 if (!realParent)
00083 {
00084 LOG(VB_GENERAL, LOG_ERR,
00085 "FATAL ERROR: Failed to cast parent to QGLWidget");
00086 return;
00087 }
00088
00089 if (!realRender)
00090 {
00091 realRender = (MythRenderOpenGL*)(realParent->context());
00092 if (!realRender)
00093 {
00094 LOG(VB_GENERAL, LOG_ERR,
00095 "FATAL ERROR: Failed to get MythRenderOpenGL");
00096 return;
00097 }
00098 }
00099
00100 DeleteTextures();
00101 realRender->makeCurrent();
00102
00103 if (target || swapControl)
00104 {
00105 realRender->BindFramebuffer(target);
00106 realRender->SetViewPort(QRect(0, 0, realParent->width(), realParent->height()));
00107 realRender->SetColor(255, 255, 255, 255);
00108 realRender->SetBackground(0, 0, 0, 0);
00109 realRender->ClearFramebuffer();
00110 }
00111 }
00112
00113 void MythOpenGLPainter::End(void)
00114 {
00115 if (!realRender)
00116 {
00117 LOG(VB_GENERAL, LOG_ERR, "FATAL ERROR: No render device in 'End'");
00118 return;
00119 }
00120 else
00121 {
00122 realRender->Flush(false);
00123 if (target == 0 && swapControl)
00124 realRender->swapBuffers();
00125 realRender->doneCurrent();
00126 }
00127
00128 MythPainter::End();
00129 }
00130
00131 int MythOpenGLPainter::GetTextureFromCache(MythImage *im)
00132 {
00133 if (!realRender)
00134 return 0;
00135
00136 if (m_ImageIntMap.contains(im))
00137 {
00138 if (!im->IsChanged())
00139 {
00140 m_ImageExpireList.remove(im);
00141 m_ImageExpireList.push_back(im);
00142 return m_ImageIntMap[im];
00143 }
00144 else
00145 {
00146 DeleteFormatImagePriv(im);
00147 }
00148 }
00149
00150 im->SetChanged(false);
00151
00152 QImage tx = QGLWidget::convertToGLFormat(*im);
00153 GLuint tx_id =
00154 realRender->CreateTexture(tx.size(), false, 0,
00155 GL_UNSIGNED_BYTE, GL_RGBA, GL_RGBA8,
00156 GL_LINEAR_MIPMAP_LINEAR);
00157
00158 if (!tx_id)
00159 {
00160 LOG(VB_GENERAL, LOG_ERR, "Failed to create OpenGL texture.");
00161 return tx_id;
00162 }
00163
00164 CheckFormatImage(im);
00165 m_HardwareCacheSize += realRender->GetTextureDataSize(tx_id);
00166 realRender->GetTextureBuffer(tx_id, false);
00167 realRender->UpdateTexture(tx_id, tx.bits());
00168
00169 m_ImageIntMap[im] = tx_id;
00170 m_ImageExpireList.push_back(im);
00171
00172 while (m_HardwareCacheSize > m_MaxHardwareCacheSize)
00173 {
00174 MythImage *expiredIm = m_ImageExpireList.front();
00175 m_ImageExpireList.pop_front();
00176 DeleteFormatImagePriv(expiredIm);
00177 DeleteTextures();
00178 }
00179
00180 return tx_id;
00181 }
00182
00183 void MythOpenGLPainter::DrawImage(const QRect &r, MythImage *im,
00184 const QRect &src, int alpha)
00185 {
00186 if (realRender)
00187 realRender->DrawBitmap(GetTextureFromCache(im), target,
00188 &src, &r, 0, alpha);
00189 }
00190
00191 void MythOpenGLPainter::DrawRect(const QRect &area, const QBrush &fillBrush,
00192 const QPen &linePen, int alpha)
00193 {
00194 if ((fillBrush.style() == Qt::SolidPattern ||
00195 fillBrush.style() == Qt::NoBrush) && realRender)
00196 {
00197 realRender->DrawRect(area, fillBrush, linePen, alpha);
00198 return;
00199 }
00200 MythPainter::DrawRect(area, fillBrush, linePen, alpha);
00201 }
00202
00203 void MythOpenGLPainter::DrawRoundRect(const QRect &area, int cornerRadius,
00204 const QBrush &fillBrush,
00205 const QPen &linePen, int alpha)
00206 {
00207 if (realRender && realRender->RectanglesAreAccelerated())
00208 {
00209 if (fillBrush.style() == Qt::SolidPattern ||
00210 fillBrush.style() == Qt::NoBrush)
00211 {
00212 realRender->DrawRoundRect(area, cornerRadius, fillBrush,
00213 linePen, alpha);
00214 return;
00215 }
00216 }
00217 MythPainter::DrawRoundRect(area, cornerRadius, fillBrush, linePen, alpha);
00218 }
00219
00220 void MythOpenGLPainter::DeleteFormatImagePriv(MythImage *im)
00221 {
00222 if (m_ImageIntMap.contains(im))
00223 {
00224 QMutexLocker locker(&m_textureDeleteLock);
00225 m_textureDeleteList.push_back(m_ImageIntMap[im]);
00226 m_ImageIntMap.remove(im);
00227 m_ImageExpireList.remove(im);
00228 }
00229 }
00230
00231 void MythOpenGLPainter::PushTransformation(const UIEffects &fx, QPointF center)
00232 {
00233 if (realRender)
00234 realRender->PushTransformation(fx, center);
00235 }
00236
00237 void MythOpenGLPainter::PopTransformation(void)
00238 {
00239 if (realRender)
00240 realRender->PopTransformation();
00241 }