MythTV master
mythvideooutopengl.cpp
Go to the documentation of this file.
1// C/C++
2#include <utility>
3
4// MythTV
12
14#include "mythplayer.h"
15#include "mythvideoprofile.h"
19#include "osd.h"
20
21#define LOC QString("VidOutGL: ")
22
30{
31 QStringList safe;
32 safe << "opengl" << "opengl-yv12";
33
34 // all profiles can handle all software frames
35 (*Options.safe_renderers)["dummy"].append(safe);
36 if (Options.decoders->contains("ffmpeg"))
37 (*Options.safe_renderers)["ffmpeg"].append(safe);
38 if (Options.decoders->contains("mediacodec-dec"))
39 (*Options.safe_renderers)["mediacodec-dec"].append(safe);
40 if (Options.decoders->contains("vaapi-dec"))
41 (*Options.safe_renderers)["vaapi-dec"].append(safe);
42 if (Options.decoders->contains("vdpau-dec"))
43 (*Options.safe_renderers)["vdpau-dec"].append(safe);
44 if (Options.decoders->contains("nvdec-dec"))
45 (*Options.safe_renderers)["nvdec-dec"].append(safe);
46 if (Options.decoders->contains("vtb-dec"))
47 (*Options.safe_renderers)["vtb-dec"].append(safe);
48 if (Options.decoders->contains("v4l2-dec"))
49 (*Options.safe_renderers)["v4l2-dec"].append(safe);
50 if (Options.decoders->contains("mmal-dec"))
51 (*Options.safe_renderers)["mmal-dec"].append(safe);
52
53 // OpenGL UYVY
54 Options.renderers->append("opengl");
55 Options.priorities->insert("opengl", 65);
56
57 // OpenGL YV12
58 Options.renderers->append("opengl-yv12");
59 Options.priorities->insert("opengl-yv12", 65);
60
61#if CONFIG_VAAPI || CONFIG_VIDEOTOOLBOX || CONFIG_MEDIACODEC || CONFIG_VDPAU || CONFIG_NVDEC || CONFIG_MMAL || CONFIG_V4L2PRIME || CONFIG_EGL
62 Options.renderers->append("opengl-hw");
63 (*Options.safe_renderers)["dummy"].append("opengl-hw");
64 Options.priorities->insert("opengl-hw", 110);
65#endif
66#if CONFIG_VAAPI
67 if (Options.decoders->contains("vaapi"))
68 (*Options.safe_renderers)["vaapi"].append("opengl-hw");
69#endif
70#if CONFIG_VIDEOTOOLBOX
71 if (Options.decoders->contains("vtb"))
72 (*Options.safe_renderers)["vtb"].append("opengl-hw");
73#endif
74#if CONFIG_MEDIACODEC
75 if (Options.decoders->contains("mediacodec"))
76 (*Options.safe_renderers)["mediacodec"].append("opengl-hw");
77#endif
78#if CONFIG_VDPAU
79 if (Options.decoders->contains("vdpau"))
80 (*Options.safe_renderers)["vdpau"].append("opengl-hw");
81#endif
82#if CONFIG_NVDEC
83 if (Options.decoders->contains("nvdec"))
84 (*Options.safe_renderers)["nvdec"].append("opengl-hw");
85#endif
86#if CONFIG_MMAL
87 if (Options.decoders->contains("mmal"))
88 (*Options.safe_renderers)["mmal"].append("opengl-hw");
89#endif
90#if CONFIG_V4L2PRIME
91 if (Options.decoders->contains("v4l2"))
92 (*Options.safe_renderers)["v4l2"].append("opengl-hw");
93#endif
94#if CONFIG_EGL
95 if (Options.decoders->contains("drmprime"))
96 (*Options.safe_renderers)["drmprime"].append("opengl-hw");
97#endif
98}
99
101 MythRenderOpenGL* Render,
102 MythOpenGLPainter* Painter,
103 MythDisplay *MDisplay,
104 const MythVideoProfilePtr& VideoProfile,
105 QString &Profile)
106 : MythVideoOutputGPU(MainWindow, Render, Painter, MDisplay, VideoProfile, Profile),
107 m_openglRender(Render)
108{
109 // Complete list of formats supported for OpenGL 2.0 and higher and OpenGL ES3.X
110 static VideoFrameTypes s_openglRenderFormats =
111 {
117 };
118
119 // OpenGL ES 2.0 and OpenGL1.X only allow luminance textures
120 static VideoFrameTypes s_openglRenderFormatsLegacy =
121 {
123 };
124
125 // Retrieve render context
126 if (!m_openglRender)
127 {
128 LOG(VB_GENERAL, LOG_ERR, LOC + "No OpenGL context");
129 return;
130 }
131
133
134 // Enable performance monitoring if requested
135 // This will report the execution time for the key GL code blocks
136 // N.B. 'Upload' should always be zero when using hardware decoding and direct
137 // rendering. Any copy cost for direct rendering will be included within 'Render'
138 if (VERBOSE_LEVEL_CHECK(VB_GPUVIDEO, LOG_INFO))
139 {
140 m_openGLPerf = new MythOpenGLPerf("GLVidPerf: ", { "Upload:", "Clear:", "Render:", "Flush:", "Swap:" });
141 if (!m_openGLPerf->isCreated())
142 {
143 delete m_openGLPerf;
144 m_openGLPerf = nullptr;
145 }
146 }
147
148 // Disallow unsupported video texturing on GLES2/GL1.X
150 m_renderFormats = &s_openglRenderFormatsLegacy;
151 else
152 m_renderFormats = &s_openglRenderFormats;
153
154 if (!qobject_cast<MythOpenGLPainter*>(m_painter))
155 LOG(VB_GENERAL, LOG_ERR, LOC + "No OpenGL painter");
156
157 // Create OpenGLVideo
159 if (m_video)
160 {
162 if (!m_video->IsValid())
163 {
164 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create valid OpenGL video");
165 delete m_video;
166 m_video = nullptr;
167 }
168 }
169}
170
172{
173 if (m_openglRender)
174 {
176 delete m_openGLPerf;
178 }
179}
180
181bool MythVideoOutputOpenGL::Init(const QSize VideoDim, const QSize VideoDispDim,
182 float Aspect, const QRect DisplayVisibleRect, MythCodecID CodecId)
183{
184 if (!(m_openglRender && m_painter && m_video))
185 {
186 LOG(VB_GENERAL, LOG_ERR, LOC + "Fatal error");
187 return false;
188 }
189
190 if (!gCoreContext->IsUIThread())
191 {
192 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot initialise OpenGL video from this thread");
193 return false;
194 }
195
197
198 if (!MythVideoOutputGPU::Init(VideoDim, VideoDispDim, Aspect, DisplayVisibleRect, CodecId))
199 return false;
200
201 // This works around an issue with VDPAU direct rendering using legacy drivers
203
204 return true;
205}
206
209{
210 QRect dvr = GetDisplayVisibleRect();
211 if (!m_mainWindow)
212 return dvr;
213
214 QSize size = m_mainWindow->size();
215
216 // may be called before m_window is initialised fully
217 if (dvr.isEmpty())
218 dvr = QRect(QPoint(0, 0), size);
219
220 // If the Video screen mode has vertically less pixels
221 // than the GUI screen mode - OpenGL coordinate adjustments
222 // must be made to put the video at the top of the display
223 // area instead of at the bottom.
224 if (dvr.height() < size.height())
225 dvr.setTop(dvr.top() - size.height() + dvr.height());
226
227 // If the Video screen mode has horizontally less pixels
228 // than the GUI screen mode - OpenGL width must be set
229 // as the higher GUI width so that the Program Guide
230 // invoked from playback is not cut off.
231 if (dvr.width() < size.width())
232 dvr.setWidth(size.width());
233
234 return dvr;
235}
236
238{
239 if (!m_openglRender)
240 return;
241
242 // Lock
244
245 // Start the first timer
246 if (m_openGLPerf)
248
249 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
250 m_openglRender->logDebugMarker(LOC + "PROCESS_FRAME_START");
251
252 // Update software frames
254
255 // Time texture update
256 if (m_openGLPerf)
258
259 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
260 m_openglRender->logDebugMarker(LOC + "PROCESS_FRAME_END");
261}
262
264{
265 if (!m_openglRender)
266 return;
267
268 // Input changes need to be handled in ProcessFrame
270 return;
271
272 // Lock
274
275 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
276 m_openglRender->logDebugMarker(LOC + "RENDER_FRAME_START");
277
278 // If process frame has not been called (double rate hardware deint), then
279 // we need to start the first 2 performance timers here
280 if (m_openGLPerf)
281 {
283 {
286 }
287 }
288
290
291 // Clear framebuffer
292 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
293 m_openglRender->logDebugMarker(LOC + "CLEAR_START");
294
295 if (!Frame || Frame->m_dummy || m_needFullClear || ((m_openglRender->GetExtraFeatures() & kGLTiled) != 0))
296 {
299 }
300 // Avoid clearing the framebuffer if it will be entirely overwritten by video
301 else if (!VideoIsFullScreen())
302 {
303 if (IsEmbedding())
304 {
305 // use MythRenderOpenGL rendering as it will clear to the appropriate 'black level'
307 }
308 else
309 {
310 // in the vast majority of cases it is significantly quicker to just
311 // clear the unused portions of the screen
312 QRegion toclear = GetBoundingRegion();
313 for (const auto& rect : std::as_const(toclear))
315 }
316 }
317
318 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
319 m_openglRender->logDebugMarker(LOC + "CLEAR_END");
320
321 // Time framebuffer clearing
322 if (m_openGLPerf)
324
325 // Render
327
328 // Time rendering
329 if (m_openGLPerf)
331
332 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
333 m_openglRender->logDebugMarker(LOC + "RENDER_FRAME_END");
334}
335
337{
338 // Flush and time
340 if (m_openGLPerf)
342}
343
345{
346 if (!m_openglRender || IsErrored())
347 return;
348
350
351 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
353
355
356 if (m_openGLPerf)
357 {
358 // Time buffer swap and log
359 // Results will normally be available on the next pass - and we will typically
360 // test every other frame as a result to avoid blocking in the driver.
361 // With the default of averaging over 30 samples this should give a 30 sample
362 // average over 60 frames
365 }
366
368}
369
372QStringList MythVideoOutputOpenGL::GetAllowedRenderers(MythRenderOpenGL *Render, MythCodecID CodecId, QSize /*VideoDim*/)
373{
374 QStringList allowed;
375 if (!Render)
376 return allowed;
377
378 if (codec_sw_copy(CodecId))
379 {
380 allowed << "opengl" << "opengl-yv12";
381 return allowed;
382 }
383
384 if (auto format = FrameTypeForCodec(CodecId); FMT_NONE != format)
385 {
387 if (MythOpenGLInterop::GetTypes(Render, supported); supported.find(format) != supported.cend())
388 allowed << "opengl-hw";
389 }
390 return allowed;
391}
std::map< VideoFrameType, InteropTypes > InteropMap
static void GetTypes(MythRender *Render, MythInteropGPU::InteropMap &Types)
A simple overload of QOpenGLTimeMonitor to record and log OpenGL execution intervals.
void RecordSample(void)
int GetTimersRunning(void) const
void LogSamples(void)
MythOpenGLVideo is responsible for displaying video frames on screen using OpenGL.
void ClearRect(QOpenGLFramebufferObject *Target, QRect Area, int Color, int Alpha)
An optimised method to clear a QRect to the given color.
void ClearFramebuffer(void)
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
void logDebugMarker(const QString &Message)
void SetBackground(uint8_t Red, uint8_t Green, uint8_t Blue, uint8_t Alpha)
int GetExtraFeatures(void) const
bool IsEmbedding(void) const
bool VideoIsFullScreen(void) const
Check whether the video display rect covers the entire window/framebuffer.
QRect GetDisplayVisibleRect(void) const
QRegion GetBoundingRegion(void) const
Return the region of DisplayVisibleRect that lies outside of DisplayVideoRect.
QRect GetWindowRect(void) const
bool IsValid() const
void SetViewportRect(QRect DisplayVisibleRect)
Common code shared between GPU accelerated sub-classes (e.g. OpenGL)
MythCodecID m_newCodecId
MythMainWindow * m_mainWindow
void PrepareFrame(MythVideoFrame *Frame, FrameScanType Scan) override
MythPainterGPU * m_painter
static VideoFrameType FrameTypeForCodec(MythCodecID CodecId)
bool Init(QSize VideoDim, QSize VideoDispDim, float Aspect, QRect DisplayVisibleRect, MythCodecID CodecId) override
void RenderFrame(MythVideoFrame *Frame, FrameScanType Scan) override
MythVideoGPU * m_video
bool Init(QSize VideoDim, QSize VideoDispDim, float Aspect, QRect DisplayVisibleRect, MythCodecID CodecId) override
void PrepareFrame(MythVideoFrame *Frame, FrameScanType Scan) override
MythRenderOpenGL * m_openglRender
MythVideoOutputOpenGL(MythMainWindow *MainWindow, MythRenderOpenGL *Render, MythOpenGLPainter *Painter, MythDisplay *Display, const MythVideoProfilePtr &VideoProfile, QString &Profile)
void RenderFrame(MythVideoFrame *Frame, FrameScanType Scan) override
QRect GetDisplayVisibleRectAdj() override
Adjust the display rectangle for OpenGL coordinates in some cases.
static void GetRenderOptions(RenderOptions &Options)
Generate the list of available OpenGL profiles.
static QStringList GetAllowedRenderers(MythRenderOpenGL *Render, MythCodecID CodecId, QSize VideoDim)
Generate a list of supported OpenGL profiles.
MythOpenGLPerf * m_openGLPerf
uint8_t m_clearColor
Definition: mythvideoout.h:96
bool IsErrored() const
MythVideoColourSpace m_videoColourSpace
Definition: mythvideoout.h:94
MythVideoProfilePtr m_videoProfile
Definition: mythvideoout.h:100
uint8_t m_clearAlpha
Definition: mythvideoout.h:97
const VideoFrameTypes * m_renderFormats
Definition: mythvideoout.h:106
MythCodecID
Definition: mythcodecid.h:14
@ kCodec_NONE
Definition: mythcodecid.h:17
static bool codec_sw_copy(MythCodecID id)
Definition: mythcodecid.h:374
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:82
@ FMT_YUV420P9
Definition: mythframe.h:24
@ FMT_YUV444P
Definition: mythframe.h:43
@ FMT_YUV420P14
Definition: mythframe.h:27
@ FMT_YUV420P12
Definition: mythframe.h:26
@ FMT_YUV422P10
Definition: mythframe.h:38
@ FMT_YUV444P16
Definition: mythframe.h:48
@ FMT_YUV422P9
Definition: mythframe.h:37
@ FMT_YUV422P14
Definition: mythframe.h:40
@ FMT_YV12
Definition: mythframe.h:23
@ FMT_P016
Definition: mythframe.h:54
@ FMT_YUV444P12
Definition: mythframe.h:46
@ FMT_YUV444P9
Definition: mythframe.h:44
@ FMT_NONE
Definition: mythframe.h:21
@ FMT_YUV444P10
Definition: mythframe.h:45
@ FMT_YUV422P
Definition: mythframe.h:36
@ FMT_YUV422P16
Definition: mythframe.h:41
@ FMT_YUV420P10
Definition: mythframe.h:25
@ FMT_YUV420P16
Definition: mythframe.h:28
@ FMT_P010
Definition: mythframe.h:53
@ FMT_NV12
Definition: mythframe.h:52
@ FMT_YUV444P14
Definition: mythframe.h:47
@ FMT_YUV422P12
Definition: mythframe.h:39
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
@ kGLLegacyTextures
@ kGLTiled
std::shared_ptr< MythVideoProfile > MythVideoProfilePtr
Definition: mythvideogpu.h:18
#define LOC
QStringList * decoders
QStringList * renderers
QMap< QString, QStringList > * safe_renderers
QMap< QString, uint > * priorities
FrameScanType
Definition: videoouttypes.h:95