00001
00002 #include <QApplication>
00003 #include <QPainter>
00004 #include <QMutex>
00005
00006
00007 #include "mythlogging.h"
00008
00009
00010 #include "mythpainter_d3d9.h"
00011
00012 #define LOC QString("D3D9 Painter: ")
00013
00014 MythD3D9Painter::MythD3D9Painter(MythRenderD3D9 *render) :
00015 MythPainter(), m_render(render), m_created_render(true), m_target(NULL),
00016 m_swap_control(true)
00017 {
00018 if (m_render)
00019 m_created_render = false;
00020 }
00021
00022 MythD3D9Painter::~MythD3D9Painter()
00023 {
00024 Teardown();
00025 }
00026
00027 bool MythD3D9Painter::InitD3D9(QPaintDevice *parent)
00028 {
00029 if (m_render)
00030 return true;
00031
00032 QWidget *real_parent = (QWidget*)parent;
00033 if (!real_parent)
00034 return false;
00035
00036 m_render = new MythRenderD3D9();
00037 if (!m_render)
00038 return false;
00039
00040 m_created_render = true;
00041 if (m_render->Create(real_parent->size(), real_parent->winId()))
00042 return true;
00043
00044 Teardown();
00045 return false;
00046 }
00047
00048 void MythD3D9Painter::Teardown(void)
00049 {
00050 ExpireImages();
00051 ClearCache();
00052 DeleteBitmaps();
00053
00054 m_ImageBitmapMap.clear();
00055 m_ImageExpireList.clear();
00056 m_bitmapDeleteList.clear();
00057
00058 if (m_render)
00059 {
00060 if (m_created_render)
00061 delete m_render;
00062 m_created_render = true;
00063 m_render = NULL;
00064 }
00065 }
00066
00067 void MythD3D9Painter::FreeResources(void)
00068 {
00069 ClearCache();
00070 DeleteBitmaps();
00071 }
00072
00073 void MythD3D9Painter::Begin(QPaintDevice *parent)
00074 {
00075 if (!m_render)
00076 {
00077 if (!InitD3D9(parent))
00078 {
00079 LOG(VB_GENERAL, LOG_ERR, "Failed to create D3D9 render.");
00080 return;
00081 }
00082 }
00083
00084 DeleteBitmaps();
00085
00086 if (!m_target)
00087 {
00088 bool dummy;
00089 m_render->Test(dummy);
00090 }
00091 else if (!m_target->SetAsRenderTarget())
00092 {
00093 LOG(VB_GENERAL, LOG_ERR, "Failed to enable offscreen buffer.");
00094 return;
00095 }
00096
00097 if (m_target)
00098 m_render->ClearBuffer();
00099 if (m_swap_control)
00100 m_render->Begin();
00101 MythPainter::Begin(parent);
00102 }
00103
00104 void MythD3D9Painter::End(void)
00105 {
00106 if (m_render)
00107 {
00108 if (m_swap_control)
00109 {
00110 m_render->End();
00111 m_render->Present(NULL);
00112 }
00113 if (m_target)
00114 m_render->SetRenderTarget(NULL);
00115 }
00116 MythPainter::End();
00117 }
00118
00119 void MythD3D9Painter::ClearCache(void)
00120 {
00121 LOG(VB_GENERAL, LOG_INFO, LOC + "Clearing D3D9 painter cache.");
00122
00123 QMutexLocker locker(&m_bitmapDeleteLock);
00124 QMapIterator<MythImage *, D3D9Image*> it(m_ImageBitmapMap);
00125 while (it.hasNext())
00126 {
00127 it.next();
00128 m_bitmapDeleteList.push_back(m_ImageBitmapMap[it.key()]);
00129 m_ImageExpireList.remove(it.key());
00130 }
00131 m_ImageBitmapMap.clear();
00132 }
00133
00134 void MythD3D9Painter::DeleteBitmaps(void)
00135 {
00136 QMutexLocker locker(&m_bitmapDeleteLock);
00137 while (!m_bitmapDeleteList.empty())
00138 {
00139 D3D9Image *img = m_bitmapDeleteList.front();
00140 m_bitmapDeleteList.pop_front();
00141 m_HardwareCacheSize -= img->GetDataSize();
00142 delete img;
00143 }
00144 }
00145
00146 void MythD3D9Painter::DrawImage(const QRect &r, MythImage *im,
00147 const QRect &src, int alpha)
00148 {
00149 D3D9Image *image = GetImageFromCache(im);
00150 if (image)
00151 {
00152 image->UpdateVertices(r, src, alpha);
00153 image->Draw();
00154 }
00155 }
00156
00157 void MythD3D9Painter::DrawRect(const QRect &area, const QBrush &fillBrush,
00158 const QPen &linePen, int alpha)
00159 {
00160 int style = fillBrush.style();
00161 if (style == Qt::SolidPattern || style == Qt::NoBrush)
00162 {
00163 if (!m_render)
00164 return;
00165
00166 if (style != Qt::NoBrush)
00167 m_render->DrawRect(area, fillBrush.color(), alpha);
00168
00169 if (linePen.style() != Qt::NoPen)
00170 {
00171 int lineWidth = linePen.width();
00172 QRect top(QPoint(area.x(), area.y()),
00173 QSize(area.width(), lineWidth));
00174 QRect bot(QPoint(area.x(), area.y() + area.height() - lineWidth),
00175 QSize(area.width(), lineWidth));
00176 QRect left(QPoint(area.x(), area.y()),
00177 QSize(lineWidth, area.height()));
00178 QRect right(QPoint(area.x() + area.width() - lineWidth, area.y()),
00179 QSize(lineWidth, area.height()));
00180 m_render->DrawRect(top, linePen.color(), alpha);
00181 m_render->DrawRect(bot, linePen.color(), alpha);
00182 m_render->DrawRect(left, linePen.color(), alpha);
00183 m_render->DrawRect(right, linePen.color(), alpha);
00184 }
00185 return;
00186 }
00187
00188 MythPainter::DrawRect(area, fillBrush, linePen, alpha);
00189 }
00190
00191 void MythD3D9Painter::DeleteFormatImagePriv(MythImage *im)
00192 {
00193 if (m_ImageBitmapMap.contains(im))
00194 {
00195 QMutexLocker locker(&m_bitmapDeleteLock);
00196 m_bitmapDeleteList.push_back(m_ImageBitmapMap[im]);
00197 m_ImageBitmapMap.remove(im);
00198 m_ImageExpireList.remove(im);
00199 }
00200 }
00201
00202 D3D9Image* MythD3D9Painter::GetImageFromCache(MythImage *im)
00203 {
00204 if (m_ImageBitmapMap.contains(im))
00205 {
00206 if (!im->IsChanged())
00207 {
00208 m_ImageExpireList.remove(im);
00209 m_ImageExpireList.push_back(im);
00210 return m_ImageBitmapMap[im];
00211 }
00212 else
00213 {
00214 DeleteFormatImagePriv(im);
00215 }
00216 }
00217
00218 im->SetChanged(false);
00219 D3D9Image *newimage = NULL;
00220 if (m_render)
00221 newimage = new D3D9Image(m_render,im->size());
00222
00223 if (newimage && newimage->IsValid())
00224 {
00225 CheckFormatImage(im);
00226 m_HardwareCacheSize += newimage->GetDataSize();
00227 newimage->UpdateImage(im);
00228 m_ImageBitmapMap[im] = newimage;
00229 m_ImageExpireList.push_back(im);
00230
00231 while (m_HardwareCacheSize > m_MaxHardwareCacheSize)
00232 {
00233 MythImage *expiredIm = m_ImageExpireList.front();
00234 m_ImageExpireList.pop_front();
00235 DeleteFormatImagePriv(expiredIm);
00236 DeleteBitmaps();
00237 }
00238 }
00239 else
00240 {
00241 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create D3D9 UI bitmap.");
00242 if (newimage)
00243 delete newimage;
00244 }
00245
00246 return newimage;
00247 }