diff --git a/mythtv/libs/libmythtv/mythvideoout.cpp b/mythtv/libs/libmythtv/mythvideoout.cpp
index ee4b759d81..f4e4d73c7e 100644
a
|
b
|
void MythVideoOutput::InitDisplayMeasurements(void) |
1020 | 1020 | .arg(displayaspect).arg(source)); |
1021 | 1021 | |
1022 | 1022 | // Get the window and screen resolutions |
1023 | | QSize window = m_window.GetWindowRect().size(); |
| 1023 | QSize window = m_window.GetWindowRect().size() / m_window.GetDevicePixelRatio(); |
1024 | 1024 | QSize screen = m_display->GetResolution(); |
1025 | 1025 | |
1026 | 1026 | // If not running fullscreen, adjust for window size and ignore any video |
diff --git a/mythtv/libs/libmythtv/videooutwindow.cpp b/mythtv/libs/libmythtv/videooutwindow.cpp
index af8af15c31..3bbd4246f3 100644
a
|
b
|
|
38 | 38 | |
39 | 39 | #define LOC QString("VideoWin: ") |
40 | 40 | |
| 41 | |
| 42 | #define SCALED_RECT(SRC, SCALE) (QRect(static_cast<int>(SRC.left() * SCALE), \ |
| 43 | static_cast<int>(SRC.top() * SCALE), \ |
| 44 | static_cast<int>(SRC.width() * SCALE), \ |
| 45 | static_cast<int>(SRC.height() * SCALE))) |
41 | 46 | static float fix_aspect(float raw); |
42 | 47 | static float snap(float value, float snapto, float diff); |
43 | 48 | |
… |
… |
void VideoOutWindow::ScreenChanged(QScreen */*screen*/) |
63 | 68 | MoveResize(); |
64 | 69 | } |
65 | 70 | |
| 71 | void VideoOutWindow::PhysicalDPIChanged(qreal /*DPI*/) |
| 72 | { |
| 73 | // FIXME - just feels wrong:) |
| 74 | |
| 75 | // revert old device pixel ratio (noop for pixel ratio = 1.0) |
| 76 | m_windowRect = m_displayVisibleRect = SCALED_RECT(m_windowRect, 1.0 / m_devicePixelRatio); |
| 77 | PopulateGeometry(); |
| 78 | // and apply new |
| 79 | m_windowRect = m_displayVisibleRect = SCALED_RECT(m_windowRect, m_devicePixelRatio); |
| 80 | MoveResize(); |
| 81 | } |
| 82 | |
66 | 83 | void VideoOutWindow::PopulateGeometry(void) |
67 | 84 | { |
68 | 85 | if (!m_display) |
… |
… |
void VideoOutWindow::PopulateGeometry(void) |
72 | 89 | if (!screen) |
73 | 90 | return; |
74 | 91 | |
| 92 | m_devicePixelRatio = screen->devicePixelRatio(); |
| 93 | |
75 | 94 | if (MythDisplay::SpanAllScreens() && MythDisplay::GetScreenCount() > 1) |
76 | 95 | { |
77 | 96 | m_screenGeometry = screen->virtualGeometry(); |
… |
… |
bool VideoOutWindow::Init(const QSize &VideoDim, const QSize &VideoDispDim, |
416 | 435 | { |
417 | 436 | m_display = Display; |
418 | 437 | connect(m_display, &MythDisplay::CurrentScreenChanged, this, &VideoOutWindow::ScreenChanged); |
| 438 | connect(m_display, &MythDisplay::PhysicalDPIChanged, this, &VideoOutWindow::PhysicalDPIChanged); |
419 | 439 | } |
420 | 440 | |
421 | 441 | if (m_display) |
… |
… |
bool VideoOutWindow::Init(const QSize &VideoDim, const QSize &VideoDispDim, |
429 | 449 | |
430 | 450 | // N.B. we are always confined to the window size so use that for the initial |
431 | 451 | // displayVisibleRect |
432 | | m_windowRect = m_displayVisibleRect = WindowRect; |
| 452 | m_windowRect = m_displayVisibleRect = SCALED_RECT(WindowRect, m_devicePixelRatio); |
433 | 453 | |
434 | 454 | int pbp_width = m_displayVisibleRect.width() / 2; |
435 | 455 | if (m_pipState == kPBPLeft || m_pipState == kPBPRight) |
… |
… |
QRegion VideoOutWindow::GetBoundingRegion(void) const |
824 | 844 | } |
825 | 845 | #endif |
826 | 846 | |
| 847 | qreal VideoOutWindow::GetDevicePixelRatio(void) const |
| 848 | { |
| 849 | return m_devicePixelRatio; |
| 850 | } |
| 851 | |
827 | 852 | /* |
828 | 853 | * \brief Determines PIP Window size and Position. |
829 | 854 | */ |
diff --git a/mythtv/libs/libmythtv/videooutwindow.h b/mythtv/libs/libmythtv/videooutwindow.h
index 9480045c92..45192f93a1 100644
a
|
b
|
class VideoOutWindow : public QObject |
45 | 45 | |
46 | 46 | public slots: |
47 | 47 | void ScreenChanged (QScreen *screen); |
| 48 | void PhysicalDPIChanged (qreal /*DPI*/); |
48 | 49 | |
49 | 50 | // Sets |
50 | 51 | void InputChanged (const QSize &VideoDim, const QSize &VideoDispDim, float Aspect); |
… |
… |
class VideoOutWindow : public QObject |
95 | 96 | #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) |
96 | 97 | QRegion GetBoundingRegion(void) const; |
97 | 98 | #endif |
| 99 | qreal GetDevicePixelRatio(void) const; |
98 | 100 | |
99 | 101 | private: |
100 | 102 | void PopulateGeometry (void); |
… |
… |
class VideoOutWindow : public QObject |
115 | 117 | bool m_dbScalingAllowed {true}; ///< disable this to prevent overscan/underscan |
116 | 118 | bool m_dbUseGUISize {false}; ///< Use the gui size for video window |
117 | 119 | QRect m_screenGeometry {0,0,1024,768}; ///< Full screen geometry |
| 120 | qreal m_devicePixelRatio {1.0}; |
118 | 121 | |
119 | 122 | // Manual Zoom |
120 | 123 | float m_manualVertScale {1.0F}; ///< Manually applied vertical scaling. |
diff --git a/mythtv/libs/libmythui/opengl/mythpainteropengl.cpp b/mythtv/libs/libmythui/opengl/mythpainteropengl.cpp
index 8fec14d3c2..e36f597f18 100644
a
|
b
|
void MythOpenGLPainter::Begin(QPaintDevice *Parent) |
109 | 109 | buf = m_render->CreateVBO(static_cast<int>(MythRenderOpenGL::kVertexSize)); |
110 | 110 | } |
111 | 111 | |
| 112 | // check for high dpi |
| 113 | m_pixelRatio = m_parent->devicePixelRatioF(); |
| 114 | QSize currentsize = m_parent->size() * m_pixelRatio; |
| 115 | |
112 | 116 | // check if we need to adjust cache sizes |
113 | | if (m_lastSize != m_parent->size()) |
| 117 | if (m_lastSize != currentsize) |
114 | 118 | { |
115 | 119 | // This will scale the cache depending on the resolution in use |
116 | 120 | static const int s_onehd = 1920 * 1080; |
117 | 121 | static const int s_basesize = 64; |
118 | | m_lastSize = m_parent->size(); |
| 122 | m_lastSize = currentsize; |
119 | 123 | float hdscreens = (static_cast<float>(m_lastSize.width() + 1) * m_lastSize.height()) / s_onehd; |
120 | 124 | int cpu = qMax(static_cast<int>(hdscreens * s_basesize), s_basesize); |
121 | 125 | int gpu = cpu * 3 / 2; |
… |
… |
void MythOpenGLPainter::Begin(QPaintDevice *Parent) |
131 | 135 | if (m_target || m_swapControl) |
132 | 136 | { |
133 | 137 | m_render->BindFramebuffer(m_target); |
134 | | m_render->SetViewPort(QRect(0, 0, m_parent->width(), m_parent->height())); |
| 138 | m_render->SetViewPort(QRect(0, 0, m_lastSize.width(), m_lastSize.height())); |
135 | 139 | m_render->SetBackground(0, 0, 0, 0); |
136 | 140 | m_render->ClearFramebuffer(); |
137 | 141 | } |
… |
… |
MythGLTexture* MythOpenGLPainter::GetTextureFromCache(MythImage *Image) |
221 | 225 | return texture; |
222 | 226 | } |
223 | 227 | |
| 228 | #define SCALED_RECT(DEST, SCALE) QRect dest = QRect(static_cast<int>(DEST.left() * SCALE), \ |
| 229 | static_cast<int>(DEST.top() * SCALE), \ |
| 230 | static_cast<int>(DEST.width() * SCALE), \ |
| 231 | static_cast<int>(DEST.height() * SCALE)); |
| 232 | |
224 | 233 | void MythOpenGLPainter::DrawImage(const QRect &Dest, MythImage *Image, |
225 | 234 | const QRect &Source, int Alpha) |
226 | 235 | { |
227 | 236 | if (m_render) |
228 | 237 | { |
229 | | // Drawing an image multiple times with the same VBO will stall most GPUs as |
| 238 | SCALED_RECT(Dest, m_pixelRatio) |
| 239 | |
| 240 | // Drawing an image multiple times with the same VBO will stall most GPUs as |
230 | 241 | // the VBO is re-mapped whilst still in use. Use a pooled VBO instead. |
231 | 242 | MythGLTexture *texture = GetTextureFromCache(Image); |
232 | 243 | if (texture && m_mappedTextures.contains(texture)) |
… |
… |
void MythOpenGLPainter::DrawImage(const QRect &Dest, MythImage *Image, |
234 | 245 | QOpenGLBuffer *vbo = texture->m_vbo; |
235 | 246 | texture->m_vbo = m_mappedBufferPool[m_mappedBufferPoolIdx]; |
236 | 247 | texture->m_destination = QRect(); |
237 | | m_render->DrawBitmap(texture, m_target, Source, Dest, nullptr, Alpha); |
| 248 | m_render->DrawBitmap(texture, m_target, Source, dest, nullptr, Alpha); |
238 | 249 | texture->m_destination = QRect(); |
239 | 250 | texture->m_vbo = vbo; |
240 | 251 | if (++m_mappedBufferPoolIdx >= MAX_BUFFER_POOL) |
… |
… |
void MythOpenGLPainter::DrawImage(const QRect &Dest, MythImage *Image, |
242 | 253 | } |
243 | 254 | else |
244 | 255 | { |
245 | | m_render->DrawBitmap(texture, m_target, Source, Dest, nullptr, Alpha); |
| 256 | m_render->DrawBitmap(texture, m_target, Source, dest, nullptr, Alpha); |
246 | 257 | m_mappedTextures.append(texture); |
247 | 258 | } |
248 | 259 | } |
… |
… |
void MythOpenGLPainter::DrawImage(const QRect &Dest, MythImage *Image, |
251 | 262 | void MythOpenGLPainter::DrawRect(const QRect &Area, const QBrush &FillBrush, |
252 | 263 | const QPen &LinePen, int Alpha) |
253 | 264 | { |
| 265 | /* |
254 | 266 | if ((FillBrush.style() == Qt::SolidPattern || |
255 | 267 | FillBrush.style() == Qt::NoBrush) && m_render) |
256 | 268 | { |
257 | 269 | m_render->DrawRect(m_target, Area, FillBrush, LinePen, Alpha); |
258 | 270 | return; |
259 | 271 | } |
| 272 | */ |
260 | 273 | MythPainter::DrawRect(Area, FillBrush, LinePen, Alpha); |
261 | 274 | } |
262 | 275 | |
… |
… |
void MythOpenGLPainter::DrawRoundRect(const QRect &Area, int CornerRadius, |
264 | 277 | const QBrush &FillBrush, |
265 | 278 | const QPen &LinePen, int Alpha) |
266 | 279 | { |
| 280 | /* |
267 | 281 | if ((FillBrush.style() == Qt::SolidPattern || |
268 | 282 | FillBrush.style() == Qt::NoBrush) && m_render) |
269 | 283 | { |
270 | | m_render->DrawRoundRect(m_target, Area, CornerRadius, FillBrush, |
271 | | LinePen, Alpha); |
| 284 | m_render->DrawRoundRect(m_target, Area, CornerRadius, FillBrush, LinePen, Alpha); |
272 | 285 | return; |
273 | 286 | } |
| 287 | */ |
274 | 288 | MythPainter::DrawRoundRect(Area, CornerRadius, FillBrush, LinePen, Alpha); |
275 | 289 | } |
276 | 290 | |
diff --git a/mythtv/libs/libmythui/opengl/mythpainteropengl.h b/mythtv/libs/libmythui/opengl/mythpainteropengl.h
index 097577231f..b4a72bd586 100644
a
|
b
|
class MUI_PUBLIC MythOpenGLPainter : public MythPainter |
60 | 60 | QOpenGLFramebufferObject* m_target { nullptr }; |
61 | 61 | bool m_swapControl { true }; |
62 | 62 | QSize m_lastSize { }; |
| 63 | qreal m_pixelRatio { 1.0 }; |
63 | 64 | |
64 | 65 | QMap<MythImage *, MythGLTexture*> m_imageToTextureMap; |
65 | 66 | std::list<MythImage *> m_ImageExpireList; |
diff --git a/mythtv/libs/libmythui/opengl/mythrenderopengl.cpp b/mythtv/libs/libmythui/opengl/mythrenderopengl.cpp
index e34320f3dc..26d4414b09 100644
a
|
b
|
void MythRenderOpenGL::SetViewPort(const QRect &Rect, bool ViewportOnly) |
579 | 579 | { |
580 | 580 | if (Rect == m_viewport) |
581 | 581 | return; |
| 582 | LOG(VB_GENERAL, LOG_INFO, LOC + QString("New viewport: %1x%2+%3+%4") |
| 583 | .arg(Rect.width()).arg(Rect.height()).arg(Rect.left()).arg(Rect.top())); |
582 | 584 | makeCurrent(); |
583 | 585 | m_viewport = Rect; |
584 | 586 | glViewport(m_viewport.left(), m_viewport.top(), |
diff --git a/mythtv/libs/libmythui/platforms/mythdisplayosx.cpp b/mythtv/libs/libmythui/platforms/mythdisplayosx.cpp
index fa2de7c4cf..68e342a2a1 100644
a
|
b
|
void MythDisplayOSX::UpdateCurrentMode(void) |
27 | 27 | { |
28 | 28 | if (!HasMythMainWindow()) |
29 | 29 | { |
| 30 | LOG(VB_GENERAL, LOG_WARNING, LOC + "Cannot update current mode"); |
30 | 31 | MythDisplay::UpdateCurrentMode(); |
31 | 32 | return; |
32 | 33 | } |
… |
… |
void MythDisplayOSX::UpdateCurrentMode(void) |
36 | 37 | CGDirectDisplayID disp = GetOSXDisplay(widget->winId()); |
37 | 38 | if (!disp) |
38 | 39 | { |
| 40 | LOG(VB_GENERAL, LOG_WARNING, LOC + "No display"); |
39 | 41 | MythDisplay::UpdateCurrentMode(); |
40 | 42 | return; |
41 | 43 | } |
42 | 44 | CGDisplayModeRef mode = CGDisplayCopyDisplayMode(disp); |
43 | 45 | if (!mode) |
44 | 46 | { |
| 47 | LOG(VB_GENERAL, LOG_WARNING, LOC + "Could not copy mode"); |
45 | 48 | MythDisplay::UpdateCurrentMode(); |
46 | 49 | return; |
47 | 50 | } |
… |
… |
bool MythDisplayOSX::UsingVideoModes(void) |
67 | 70 | |
68 | 71 | const std::vector<MythDisplayMode>& MythDisplayOSX::GetVideoModes(void) |
69 | 72 | { |
70 | | if (!m_videoModes.empty() || !HasMythMainWindow()) |
| 73 | if (!m_videoModes.empty()) |
71 | 74 | return m_videoModes; |
72 | 75 | |
| 76 | if (!HasMythMainWindow()) |
| 77 | { |
| 78 | LOG(VB_GENERAL, LOG_WARNING, LOC + "Cannot retrieve modes"); |
| 79 | return m_videoModes; |
| 80 | } |
| 81 | |
73 | 82 | ClearModes(); |
74 | 83 | |
75 | 84 | WId win = (qobject_cast<QWidget*>(MythMainWindow::getMainWindow()))->winId(); |
… |
… |
const std::vector<MythDisplayMode>& MythDisplayOSX::GetVideoModes(void) |
83 | 92 | DisplayModeMap screen_map; |
84 | 93 | CGSize sizemm = CGDisplayScreenSize(disp); |
85 | 94 | |
| 95 | LOG(VB_GENERAL, LOG_INFO, LOC + "Raw video mode sizes:"); |
86 | 96 | for (int i = 0; i < CFArrayGetCount(modes); ++i) |
87 | 97 | { |
88 | 98 | CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); |
… |
… |
const std::vector<MythDisplayMode>& MythDisplayOSX::GetVideoModes(void) |
90 | 100 | bool interlaced = CGDisplayModeGetIOFlags(mode) & kDisplayModeInterlacedFlag; |
91 | 101 | int width = static_cast<int>(CGDisplayModeGetWidth(mode)); |
92 | 102 | int height = static_cast<int>(CGDisplayModeGetHeight(mode)); |
| 103 | int widthp = static_cast<int>(CGDisplayModeGetPixelWidth(mode)); |
| 104 | int heightp = static_cast<int>(CGDisplayModeGetPixelHeight(mode)); |
| 105 | |
| 106 | LOG(VB_GENERAL, LOG_INFO, LOC + QString("Resolution: %1x%2 PixelSize: %3x%4") |
| 107 | .arg(width).arg(height).arg(widthp).arg(heightp)); |
93 | 108 | |
94 | 109 | // See note in MythDisplayX11 |
95 | 110 | if (interlaced) |
… |
… |
const std::vector<MythDisplayMode>& MythDisplayOSX::GetVideoModes(void) |
120 | 135 | bool MythDisplayOSX::SwitchToVideoMode(QSize Size, double DesiredRate) |
121 | 136 | { |
122 | 137 | if (!HasMythMainWindow()) |
| 138 | { |
| 139 | LOG(VB_GENERAL, LOG_WARNING, LOC + "Cannot switch mode"); |
123 | 140 | return false; |
| 141 | } |
| 142 | |
124 | 143 | WId win = (qobject_cast<QWidget*>(MythMainWindow::getMainWindow()))->winId(); |
125 | 144 | CGDirectDisplayID disp = GetOSXDisplay(win); |
126 | 145 | if (!disp) |
| 146 | { |
| 147 | LOG(VB_GENERAL, LOG_WARNING, LOC + "No display"); |
127 | 148 | return false; |
| 149 | } |
128 | 150 | |
129 | 151 | auto rate = static_cast<double>(NAN); |
130 | 152 | MythDisplayMode desired(Size, QSize(0, 0), -1.0, DesiredRate); |
… |
… |
bool MythDisplayOSX::SwitchToVideoMode(QSize Size, double DesiredRate) |
147 | 169 | CGDisplayConfigRef cfg; |
148 | 170 | CGBeginDisplayConfiguration(&cfg); |
149 | 171 | CGConfigureDisplayFadeEffect(cfg, 0.3f, 0.5f, 0, 0, 0); |
150 | | CGDisplaySetDisplayMode(disp, m_modeMap.value(mode), nullptr); |
151 | | CGError err = CGCompleteDisplayConfiguration(cfg, kCGConfigureForAppOnly); |
| 172 | CGError err = CGDisplaySetDisplayMode(disp, m_modeMap.value(mode), nullptr); |
| 173 | if (err != kCGErrorSuccess) |
| 174 | LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to set display mode (%1)").arg(err)); |
| 175 | err = CGCompleteDisplayConfiguration(cfg, kCGConfigureForAppOnly); |
152 | 176 | CGDisplayRelease(disp); |
153 | 177 | return err == kCGErrorSuccess; |
154 | 178 | } |