MythTV  master
mythdisplayx11.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "config.h"
3 #include "mythcorecontext.h"
4 #include "mythlogging.h"
5 #include "mythdisplayx11.h"
6 
7 // X11
8 #include <X11/Xatom.h>
9 
10 #define LOC QString("DisplayX11: ")
11 
13 {
14  Initialise();
15 }
16 
18 {
19  static bool s_checked = false;
20  static bool s_available = false;
21  if (!s_checked)
22  {
23  s_checked = true;
24  MythXDisplay display;
25  s_available = display.Open();
26  }
27  return s_available;
28 }
29 
44 {
45  // Get some Qt basics first
47 
49  if (display)
50  {
51  // XRANDR should always be accurate
52  GetEDID(display);
53  XRRScreenResources* res = XRRGetScreenResourcesCurrent(display->GetDisplay(), display->GetRoot());
54  XRROutputInfo *output = GetOutput(res, display, m_screen);
55  if (output)
56  {
57  m_physicalSize = QSize(static_cast<int>(output->mm_width),
58  static_cast<int>(output->mm_height));
59  XRRFreeOutputInfo(output);
60  }
61 
62  if (!m_crtc)
63  (void)GetVideoModes();
64  while (m_crtc && res)
65  {
66  XRRCrtcInfo *currentcrtc = XRRGetCrtcInfo(display->GetDisplay(), res, m_crtc);
67  if (!currentcrtc)
68  break;
69  for (int i = 0; i < res->nmode; ++i)
70  {
71  if (res->modes[i].id != currentcrtc->mode)
72  continue;
73  XRRModeInfo mode = res->modes[i];
74  m_resolution = QSize(static_cast<int>(mode.width),
75  static_cast<int>(mode.height));
76  if (mode.dotClock > 1 && mode.vTotal > 1 && mode.hTotal > 1)
77  {
78  m_refreshRate = static_cast<double>(mode.dotClock) / (mode.vTotal * mode.hTotal);
79  if (mode.modeFlags & RR_Interlace)
80  m_refreshRate *= 2.0;
81  }
82  }
83  XRRFreeCrtcInfo(currentcrtc);
84  break;
85  }
86  XRRFreeScreenResources(res);
87 
88  delete display;
89  m_modeComplete = true;
90  return;
91  }
92 }
93 
95 {
96  if (gCoreContext)
97  return gCoreContext->GetBoolSetting("UseVideoModes", false);
98  return false;
99 }
100 
101 const std::vector<MythDisplayMode>& MythDisplayX11::GetVideoModes(void)
102 {
103  if (!m_videoModes.empty() || !m_screen)
104  return m_videoModes;
105 
106  m_videoModes.clear();
107  m_modeMap.clear();
108 
110  if (!display)
111  return m_videoModes;
112 
113  XRRScreenResources* res = XRRGetScreenResourcesCurrent(display->GetDisplay(), display->GetRoot());
114  XRROutputInfo *output = GetOutput(res, display, m_screen);
115 
116  if (!output)
117  {
118  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find an output that matches '%1'")
119  .arg(m_screen->name()));
120  XRRFreeScreenResources(res);
121  delete display;
122  return m_videoModes;
123  }
124 
125  int mmwidth = static_cast<int>(output->mm_width);
126  int mmheight = static_cast<int>(output->mm_height);
127  m_crtc = output->crtc;
128 
129  DisplayModeMap screenmap;
130  for (int i = 0; i < output->nmode; ++i)
131  {
132  RRMode rrmode = output->modes[i];
133  for (int j = 0; j < res->nmode; ++j)
134  {
135  if (res->modes[j].id != rrmode)
136  continue;
137 
138  XRRModeInfo mode = res->modes[j];
139  if (mode.id != rrmode)
140  continue;
141  if (!(mode.dotClock > 1 && mode.vTotal > 1 && mode.hTotal > 1))
142  continue;
143  int width = static_cast<int>(mode.width);
144  int height = static_cast<int>(mode.height);
145  double rate = static_cast<double>(mode.dotClock) / (mode.vTotal * mode.hTotal);
146  bool interlaced = (mode.modeFlags & RR_Interlace) != 0U;
147  if (interlaced)
148  rate *= 2.0;
149 
150  // TODO don't filter out interlaced modes but ignore them in MythDisplayMode
151  // when not required. This may then be used in future to allow 'exact' match
152  // display modes to display interlaced material on interlaced displays
153  if (interlaced)
154  {
155  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Ignoring interlaced mode %1x%2 %3i")
156  .arg(width).arg(height).arg(rate, 2, 'f', 2, '0'));
157  continue;
158  }
159 
160  QSize resolution(width, height);
161  QSize physical(mmwidth, mmheight);
162  uint64_t key = MythDisplayMode::CalcKey(resolution, 0.0);
163  if (screenmap.find(key) == screenmap.end())
164  screenmap[key] = MythDisplayMode(resolution, physical, -1.0, rate);
165  else
166  screenmap[key].AddRefreshRate(rate);
167  m_modeMap.insert(MythDisplayMode::CalcKey(resolution, rate), rrmode);
168  }
169  }
170 
171  for (auto it = screenmap.begin(); screenmap.end() != it; ++it)
172  m_videoModes.push_back(it->second);
173 
174  DebugModes();
175  XRRFreeOutputInfo(output);
176  XRRFreeScreenResources(res);
177  delete display;
178  return m_videoModes;
179 }
180 
181 bool MythDisplayX11::SwitchToVideoMode(QSize Size, double DesiredRate)
182 {
183  if (!m_crtc)
184  (void)GetVideoModes();
185  if (!m_crtc)
186  return false;
187 
188  auto rate = static_cast<double>(NAN);
189  QSize dummy(0, 0);
190  MythDisplayMode desired(Size, dummy, -1.0, DesiredRate);
191  int idx = MythDisplayMode::FindBestMatch(m_videoModes, desired, rate);
192 
193  if (idx < 0)
194  {
195  LOG(VB_GENERAL, LOG_ERR, LOC + "Desired resolution and frame rate not found.");
196  return false;
197  }
198 
199  auto mode = MythDisplayMode::CalcKey(Size, rate);
200  if (!m_modeMap.contains(mode))
201  {
202  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find mode");
203  return false;
204  }
205 
207  if (!display)
208  return false;
209 
210  Status status = RRSetConfigFailed;
211  XRRScreenResources* res = XRRGetScreenResourcesCurrent(display->GetDisplay(), display->GetRoot());
212  if (res)
213  {
214  XRRCrtcInfo *currentcrtc = XRRGetCrtcInfo(display->GetDisplay(), res, m_crtc);
215  if (currentcrtc)
216  {
217  status = XRRSetCrtcConfig(display->GetDisplay(), res, m_crtc, CurrentTime,
218  currentcrtc->x, currentcrtc->y, m_modeMap.value(mode),
219  currentcrtc->rotation, currentcrtc->outputs,
220  currentcrtc->noutput);
221  XRRFreeCrtcInfo(currentcrtc);
222  XRRScreenConfiguration *config = XRRGetScreenInfo(display->GetDisplay(), display->GetRoot());
223  if (config)
224  XRRFreeScreenConfigInfo(config);
225  }
226  XRRFreeScreenResources(res);
227  }
228  delete display;
229 
230  if (RRSetConfigSuccess != status)
231  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set video mode");
232  return RRSetConfigSuccess == status;
233 }
234 
235 XRROutputInfo* MythDisplayX11::GetOutput(XRRScreenResources* Resources,
236  MythXDisplay* mDisplay,
237  QScreen* qScreen, RROutput *Output)
238 {
239  if (!(Resources && mDisplay && qScreen))
240  return nullptr;
241 
242  XRROutputInfo *result = nullptr;
243  for (int i = 0; i < Resources->noutput; ++i)
244  {
245  if (result)
246  {
247  XRRFreeOutputInfo(result);
248  result = nullptr;
249  }
250 
251  result = XRRGetOutputInfo(mDisplay->GetDisplay(), Resources, Resources->outputs[i]);
252  if (!result || result->nameLen < 1)
253  continue;
254  if (result->connection != RR_Connected)
255  {
256  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Output '%1' is disconnected")
257  .arg(result->name));
258  continue;
259  }
260 
261  QString name(result->name);
262  if (name == qScreen->name())
263  {
264  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Matched '%1' to output %2")
265  .arg(qScreen->name()).arg(Resources->outputs[i]));
266  if (Output)
267  *Output = Resources->outputs[i];
268  return result;
269  }
270  }
271  XRRFreeOutputInfo(result);
272  return nullptr;
273 }
274 
276 {
277  if (!mDisplay)
278  {
279  m_edid = MythEDID();
280  return;
281  }
282 
283  XRRScreenResources* res = XRRGetScreenResourcesCurrent(mDisplay->GetDisplay(), mDisplay->GetRoot());
284  RROutput rroutput = 0;
285  XRROutputInfo *output = GetOutput(res, mDisplay, m_screen, &rroutput);
286 
287  while (rroutput)
288  {
289  Atom edidproperty = XInternAtom(mDisplay->GetDisplay(), RR_PROPERTY_RANDR_EDID,
290  static_cast<Bool>(false));
291  if (!edidproperty)
292  break;
293 
294  int propertycount = 0;
295  Atom* properties = XRRListOutputProperties(mDisplay->GetDisplay(), rroutput, &propertycount);
296  if (!properties)
297  break;
298 
299  bool found = false;
300  for (int i = 0; i < propertycount; ++i)
301  {
302  if (properties[i] == edidproperty)
303  {
304  found = true;
305  break;
306  }
307  }
308  XFree(properties);
309  if (!found)
310  break;
311 
312  Atom actualtype = 0;
313  int actualformat = 0;;
314  unsigned long bytesafter = 0;
315  unsigned long nitems = 0;
316  unsigned char* data = nullptr;
317  if (XRRGetOutputProperty(mDisplay->GetDisplay(), rroutput, edidproperty,
318  0, 128, static_cast<Bool>(false), static_cast<Bool>(false),
319  AnyPropertyType, &actualtype,
320  &actualformat, &nitems, &bytesafter, &data) == Success)
321  {
322  if (actualtype == XA_INTEGER && actualformat == 8)
323  m_edid = MythEDID(reinterpret_cast<const char*>(data),
324  static_cast<int>(nitems));
325  }
326  break;
327  }
328  XRRFreeOutputInfo(output);
329  XRRFreeScreenResources(res);
330 }
MythDisplay::m_physicalSize
QSize m_physicalSize
Definition: mythdisplay.h:89
MythDisplayX11::GetVideoModes
const std::vector< MythDisplayMode > & GetVideoModes(void) override
Definition: mythdisplayx11.cpp:101
MythDisplay::DebugModes
void DebugModes(void) const
Definition: mythdisplay.cpp:1025
MythDisplayX11::m_modeMap
QMap< uint64_t, unsigned long > m_modeMap
Definition: mythdisplayx11.h:33
MythDisplay::Initialise
void Initialise(void)
Definition: mythdisplay.cpp:493
MythDisplay::m_resolution
QSize m_resolution
Definition: mythdisplay.h:88
MythXDisplay::Open
bool Open(void)
Open the display.
Definition: mythxdisplay.cpp:84
MythDisplayX11::GetOutput
static XRROutputInfo * GetOutput(XRRScreenResources *Resources, MythXDisplay *mDisplay, QScreen *qScreen, RROutput *Output=nullptr)
Definition: mythdisplayx11.cpp:235
MythDisplayX11::SwitchToVideoMode
bool SwitchToVideoMode(QSize Size, double DesiredRate) override
Definition: mythdisplayx11.cpp:181
MythDisplayMode::CalcKey
static uint64_t CalcKey(QSize Size, double Rate)
Definition: mythdisplaymode.cpp:126
MythDisplay::UpdateCurrentMode
virtual void UpdateCurrentMode(void)
Retrieve screen details.
Definition: mythdisplay.cpp:431
arg
arg(title).arg(filename).arg(doDelete))
MythDisplayX11::UpdateCurrentMode
void UpdateCurrentMode(void) override
Retrieve details for the current video mode.
Definition: mythdisplayx11.cpp:43
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
DisplayModeMap
map< uint64_t, MythDisplayMode > DisplayModeMap
Definition: mythdisplaymode.h:19
MythDisplay::m_videoModes
vector< MythDisplayMode > m_videoModes
Definition: mythdisplay.h:94
MythDisplay::m_modeComplete
bool m_modeComplete
Definition: mythdisplay.h:85
MythXDisplay::OpenMythXDisplay
static MythXDisplay * OpenMythXDisplay(bool Warn=true)
Definition: mythxdisplay.cpp:44
MythDisplayX11::UsingVideoModes
bool UsingVideoModes(void) override
Definition: mythdisplayx11.cpp:94
MythXDisplay::GetRoot
Window GetRoot(void) const
Definition: mythxdisplay.h:36
MythDisplayX11::MythDisplayX11
MythDisplayX11()
Definition: mythdisplayx11.cpp:12
mythlogging.h
MythDisplay::m_edid
MythEDID m_edid
Definition: mythdisplay.h:90
MythDisplayX11::m_crtc
unsigned long m_crtc
Definition: mythdisplayx11.h:34
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythXDisplay::GetDisplay
Display * GetDisplay(void)
Definition: mythxdisplay.h:30
MythDisplayMode
Definition: mythdisplaymode.h:22
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:924
MythDisplayMode::FindBestMatch
static int FindBestMatch(const vector< MythDisplayMode > &Modes, const MythDisplayMode &Mode, double &TargetRate)
Definition: mythdisplaymode.cpp:139
MythDisplay::m_refreshRate
double m_refreshRate
Definition: mythdisplay.h:86
MythDisplayX11::IsAvailable
static bool IsAvailable(void)
Definition: mythdisplayx11.cpp:17
mythcorecontext.h
MythXDisplay
Definition: mythxdisplay.h:22
MythDisplay::m_screen
QScreen * m_screen
Definition: mythdisplay.h:93
MythDisplay::GetEDID
MythEDID & GetEDID(void)
Definition: mythdisplay.cpp:847
LOC
#define LOC
Definition: mythdisplayx11.cpp:10
mythdisplayx11.h
output
#define output
Definition: synaesthesia.cpp:221
Resources
QList< Resource * > Resources
Definition: upnpcdsobjects.h:127
MythEDID
Definition: mythedid.h:15