00001
00002 #include "config.h"
00003 #include "DisplayResX.h"
00004
00005 #include <cmath>
00006
00007 #include "mythlogging.h"
00008 #include "mythdb.h"
00009 #include "mythdisplay.h"
00010 #include "mythxdisplay.h"
00011 #include "util-nvctrl.h"
00012
00013 #include <X11/extensions/Xrandr.h>
00014
00015 static XRRScreenConfiguration *GetScreenConfig(MythXDisplay*& display);
00016
00017 DisplayResX::DisplayResX(void)
00018 {
00019 Initialize();
00020 }
00021
00022 DisplayResX::~DisplayResX(void)
00023 {
00024 }
00025
00026 bool DisplayResX::GetDisplayInfo(int &w_pix, int &h_pix, int &w_mm,
00027 int &h_mm, double &rate, double &par) const
00028 {
00029 DisplayInfo info = MythDisplay::GetDisplayInfo();
00030 w_mm = info.size.width();
00031 h_mm = info.size.height();
00032 w_pix = info.res.width();
00033 h_pix = info.res.height();
00034 rate = 1000000.0f / info.rate;
00035 par = 1.0;
00036
00037 if (w_mm > 0 && h_mm > 0 && w_pix > 0 && h_pix > 0)
00038 par = ((double)w_mm / (double)w_pix) / ((double)h_mm / (double)h_pix);
00039
00040 return true;
00041 }
00042
00043 bool DisplayResX::SwitchToVideoMode(int width, int height, double desired_rate)
00044 {
00045 double rate;
00046 DisplayResScreen desired_screen(width, height, 0, 0, -1.0, desired_rate);
00047 int idx = DisplayResScreen::FindBestMatch(m_videoModesUnsorted,
00048 desired_screen, rate);
00049
00050 if (idx >= 0)
00051 {
00052 short finalrate;
00053 MythXDisplay *display = NULL;
00054 XRRScreenConfiguration *cfg = GetScreenConfig(display);
00055
00056 if (!cfg)
00057 return false;
00058
00059 Rotation rot;
00060
00061 XRRConfigCurrentConfiguration(cfg, &rot);
00062
00063
00064 finalrate = (short) rate;
00065
00066 for (uint i = 0; i < m_videoModes.size(); i++)
00067 {
00068 if ((m_videoModes[i].Width() == width) &&
00069 (m_videoModes[i].Height() == height))
00070 {
00071 if (m_videoModes[i].Custom())
00072 {
00073 finalrate = m_videoModes[i].realRates[rate];
00074 LOG(VB_PLAYBACK, LOG_INFO,
00075 QString("Dynamic TwinView rate found, set %1Hz as "
00076 "XRandR %2") .arg(rate) .arg(finalrate));
00077 }
00078
00079 break;
00080 }
00081 }
00082
00083 Window root = display->GetRoot();
00084
00085 Status status = XRRSetScreenConfigAndRate(display->GetDisplay(), cfg,
00086 root, idx, rot, finalrate,
00087 CurrentTime);
00088
00089 XRRFreeScreenConfigInfo(cfg);
00090 delete display;
00091
00092 if (RRSetConfigSuccess != status)
00093 LOG(VB_GENERAL, LOG_ERR,
00094 "XRRSetScreenConfigAndRate() call failed.");
00095
00096 return RRSetConfigSuccess == status;
00097 }
00098
00099 LOG(VB_GENERAL, LOG_ERR, "Desired Resolution and FrameRate not found.");
00100
00101 return false;
00102 }
00103
00104 const DisplayResVector& DisplayResX::GetVideoModes(void) const
00105 {
00106 if (!m_videoModes.empty())
00107 return m_videoModes;
00108
00109 MythXDisplay *display = NULL;
00110
00111 XRRScreenConfiguration *cfg = GetScreenConfig(display);
00112
00113 if (!cfg)
00114 return m_videoModes;
00115
00116 int num_sizes, num_rates;
00117
00118 XRRScreenSize *sizes = NULL;
00119
00120 sizes = XRRConfigSizes(cfg, &num_sizes);
00121
00122 for (int i = 0; i < num_sizes; ++i)
00123 {
00124 short *rates = NULL;
00125 rates = XRRRates(display->GetDisplay(), display->GetScreen(),
00126 i, &num_rates);
00127 DisplayResScreen scr(sizes[i].width, sizes[i].height,
00128 sizes[i].mwidth, sizes[i].mheight,
00129 rates, num_rates);
00130 m_videoModes.push_back(scr);
00131 }
00132
00133 t_screenrate screenmap;
00134
00135 int nvidiarate = GetNvidiaRates(screenmap);
00136
00137 if (nvidiarate > 0)
00138 {
00139
00140
00141 for (uint i = 0; i < m_videoModes.size(); i++)
00142 {
00143 DisplayResScreen scr = m_videoModes[i];
00144 int w = scr.Width();
00145 int h = scr.Height();
00146 int mw = scr.Width_mm();
00147 int mh = scr.Height_mm();
00148 std::vector<double> newrates;
00149 std::map<double, short> realRates;
00150 const std::vector<double>& rates = scr.RefreshRates();
00151 bool found = false;
00152
00153 for (std::vector<double>::const_iterator it = rates.begin();
00154 it != rates.end(); ++it)
00155 {
00156 uint64_t key = DisplayResScreen::CalcKey(w, h, *it);
00157
00158 if (screenmap.find(key) != screenmap.end())
00159 {
00160
00161 newrates.push_back(screenmap[key]);
00162 realRates[screenmap[key]] = (int) round(*it);
00163 found = true;
00164 #if 0
00165 LOG(VB_PLAYBACK, LOG_INFO,
00166 QString("CustomRate Found, set %1x%2@%3 as %4Hz")
00167 .arg(w) .arg(h) .arg(*it) .arg(screenmap[key]));
00168 #endif
00169 }
00170 }
00171
00172 if (found)
00173 {
00174 m_videoModes.erase(m_videoModes.begin() + i);
00175 std::sort(newrates.begin(), newrates.end());
00176 m_videoModes.insert(m_videoModes.begin() + i,
00177 DisplayResScreen(w, h, mw, mh, newrates,
00178 realRates));
00179 }
00180 }
00181 }
00182
00183 m_videoModesUnsorted = m_videoModes;
00184
00185 std::sort(m_videoModes.begin(), m_videoModes.end());
00186 XRRFreeScreenConfigInfo(cfg);
00187 delete display;
00188
00189 return m_videoModes;
00190 }
00191
00192 static XRRScreenConfiguration *GetScreenConfig(MythXDisplay*& display)
00193 {
00194 display = OpenMythXDisplay();
00195
00196 if (!display)
00197 {
00198 LOG(VB_GENERAL, LOG_ERR, "DisplaResX: MythXOpenDisplay call failed");
00199 return NULL;
00200 }
00201
00202 Window root = RootWindow(display->GetDisplay(), display->GetScreen());
00203
00204 XRRScreenConfiguration *cfg = NULL;
00205 int event_basep = 0, error_basep = 0;
00206
00207 if (XRRQueryExtension(display->GetDisplay(), &event_basep, &error_basep))
00208 cfg = XRRGetScreenInfo(display->GetDisplay(), root);
00209
00210 if (!cfg)
00211 {
00212 delete display;
00213 display = NULL;
00214 LOG(VB_GENERAL, LOG_ERR, "DisplaResX: Unable to XRRgetScreenInfo");
00215 }
00216
00217 return cfg;
00218 }