MythTV master
mythvideooutopengl.cpp
Go to the documentation of this file.
1// C/C++
2#include <utility>
3
4// MythTV
5#include "libmythbase/mythconfig.h"
13
15#include "mythplayer.h"
16#include "mythvideoprofile.h"
20#include "osd.h"
21
22#define LOC QString("VidOutGL: ")
23
31{
32 QStringList safe;
33 safe << "opengl" << "opengl-yv12";
34
35 // all profiles can handle all software frames
36 (*Options.safe_renderers)["dummy"].append(safe);
37 if (Options.decoders->contains("ffmpeg"))
38 (*Options.safe_renderers)["ffmpeg"].append(safe);
39 if (Options.decoders->contains("mediacodec-dec"))
40 (*Options.safe_renderers)["mediacodec-dec"].append(safe);
41 if (Options.decoders->contains("vaapi-dec"))
42 (*Options.safe_renderers)["vaapi-dec"].append(safe);
43 if (Options.decoders->contains("vdpau-dec"))
44 (*Options.safe_renderers)["vdpau-dec"].append(safe);
45 if (Options.decoders->contains("nvdec-dec"))
46 (*Options.safe_renderers)["nvdec-dec"].append(safe);
47 if (Options.decoders->contains("vtb-dec"))
48 (*Options.safe_renderers)["vtb-dec"].append(safe);
49 if (Options.decoders->contains("v4l2-dec"))
50 (*Options.safe_renderers)["v4l2-dec"].append(safe);
51 if (Options.decoders->contains("mmal-dec"))
52 (*Options.safe_renderers)["mmal-dec"].append(safe);
53
54 // OpenGL UYVY
55 Options.renderers->append("opengl");
56 Options.priorities->insert("opengl", 65);
57
58 // OpenGL YV12
59 Options.renderers->append("opengl-yv12");
60 Options.priorities->insert("opengl-yv12", 65);
61
62#if CONFIG_VAAPI || CONFIG_VIDEOTOOLBOX || CONFIG_MEDIACODEC || CONFIG_VDPAU || CONFIG_NVDEC || CONFIG_MMAL || CONFIG_V4L2PRIME || CONFIG_EGL
63 Options.renderers->append("opengl-hw");
64 (*Options.safe_renderers)["dummy"].append("opengl-hw");
65 Options.priorities->insert("opengl-hw", 110);
66#endif
67#if CONFIG_VAAPI
68 if (Options.decoders->contains("vaapi"))
69 (*Options.safe_renderers)["vaapi"].append("opengl-hw");
70#endif
71#if CONFIG_VIDEOTOOLBOX
72 if (Options.decoders->contains("vtb"))
73 (*Options.safe_renderers)["vtb"].append("opengl-hw");
74#endif
75#if CONFIG_MEDIACODEC
76 if (Options.decoders->contains("mediacodec"))
77 (*Options.safe_renderers)["mediacodec"].append("opengl-hw");
78#endif
79#if CONFIG_VDPAU
80 if (Options.decoders->contains("vdpau"))
81 (*Options.safe_renderers)["vdpau"].append("opengl-hw");
82#endif
83#if CONFIG_NVDEC
84 if (Options.decoders->contains("nvdec"))
85 (*Options.safe_renderers)["nvdec"].append("opengl-hw");
86#endif
87#if CONFIG_MMAL
88 if (Options.decoders->contains("mmal"))
89 (*Options.safe_renderers)["mmal"].append("opengl-hw");
90#endif
91#if CONFIG_V4L2PRIME
92 if (Options.decoders->contains("v4l2"))
93 (*Options.safe_renderers)["v4l2"].append("opengl-hw");
94#endif
95#if CONFIG_EGL
96 if (Options.decoders->contains("drmprime"))
97 (*Options.safe_renderers)["drmprime"].append("opengl-hw");
98#endif
99}
100
102 MythRenderOpenGL* Render,
103 MythOpenGLPainter* Painter,
104 MythDisplay *MDisplay,
105 const MythVideoProfilePtr& VideoProfile,
106 QString &Profile)
107 : MythVideoOutputGPU(MainWindow, Render, Painter, MDisplay, VideoProfile, Profile),
108 m_openglRender(Render)
109{
110 // Complete list of formats supported for OpenGL 2.0 and higher and OpenGL ES3.X
111 static VideoFrameTypes s_openglRenderFormats =
112 {
118 };
119
120 // OpenGL ES 2.0 and OpenGL1.X only allow luminance textures
121 static VideoFrameTypes s_openglRenderFormatsLegacy =
122 {
124 };
125
126 // Retrieve render context
127 if (!m_openglRender)
128 {
129 LOG(VB_GENERAL, LOG_ERR, LOC + "No OpenGL context");
130 return;
131 }
132
134
135 // Enable performance monitoring if requested
136 // This will report the execution time for the key GL code blocks
137 // N.B. 'Upload' should always be zero when using hardware decoding and direct
138 // rendering. Any copy cost for direct rendering will be included within 'Render'
139 if (VERBOSE_LEVEL_CHECK(VB_GPUVIDEO, LOG_INFO))
140 {
141 m_openGLPerf = new MythOpenGLPerf("GLVidPerf: ", { "Upload:", "Clear:", "Render:", "Flush:", "Swap:" });
142 if (!m_openGLPerf->isCreated())
143 {
144 delete m_openGLPerf;
145 m_openGLPerf = nullptr;
146 }
147 }
148
149 // Disallow unsupported video texturing on GLES2/GL1.X
151 m_renderFormats = &s_openglRenderFormatsLegacy;
152 else
153 m_renderFormats = &s_openglRenderFormats;
154
155 if (!qobject_cast<MythOpenGLPainter*>(m_painter))
156 LOG(VB_GENERAL, LOG_ERR, LOC + "No OpenGL painter");
157
158 // Create OpenGLVideo
160 if (m_video)
161 {
163 if (!m_video->IsValid())
164 {
165 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create valid OpenGL video");
166 delete m_video;
167 m_video = nullptr;
168 }
169 }
170}
171
173{
174 if (m_openglRender)
175 {
177 delete m_openGLPerf;
179 }
180}
181
182bool MythVideoOutputOpenGL::Init(const QSize VideoDim, const QSize VideoDispDim,
183 float Aspect, const QRect DisplayVisibleRect, MythCodecID CodecId)
184{
185 if (!(m_openglRender && m_painter && m_video))
186 {
187 LOG(VB_GENERAL, LOG_ERR, LOC + "Fatal error");
188 return false;
189 }
190
191 if (!gCoreContext->IsUIThread())
192 {
193 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot initialise OpenGL video from this thread");
194 return false;
195 }
196
198
199 if (!MythVideoOutputGPU::Init(VideoDim, VideoDispDim, Aspect, DisplayVisibleRect, CodecId))
200 return false;
201
202 // This works around an issue with VDPAU direct rendering using legacy drivers
204
205 return true;
206}
207
210{
211 QRect dvr = GetDisplayVisibleRect();
212 if (!m_mainWindow)
213 return dvr;
214
215 QSize size = m_mainWindow->size();
216
217 // may be called before m_window is initialised fully
218 if (dvr.isEmpty())
219 dvr = QRect(QPoint(0, 0), size);
220
221 // If the Video screen mode has vertically less pixels
222 // than the GUI screen mode - OpenGL coordinate adjustments
223 // must be made to put the video at the top of the display
224 // area instead of at the bottom.
225 if (dvr.height() < size.height())
226 dvr.setTop(dvr.top() - size.height() + dvr.height());
227
228 // If the Video screen mode has horizontally less pixels
229 // than the GUI screen mode - OpenGL width must be set
230 // as the higher GUI width so that the Program Guide
231 // invoked from playback is not cut off.
232 if (dvr.width() < size.width())
233 dvr.setWidth(size.width());
234
235 return dvr;
236}
237
239{
240 if (!m_openglRender)
241 return;
242
243 // Lock
245
246 // Start the first timer
247 if (m_openGLPerf)
249
250 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
251 m_openglRender->logDebugMarker(LOC + "PROCESS_FRAME_START");
252
253 // Update software frames
255
256 // Time texture update
257 if (m_openGLPerf)
259
260 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
261 m_openglRender->logDebugMarker(LOC + "PROCESS_FRAME_END");
262}
263
265{
266 if (!m_openglRender)
267 return;
268
269 // Input changes need to be handled in ProcessFrame
271 return;
272
273 // Lock
275
276 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
277 m_openglRender->logDebugMarker(LOC + "RENDER_FRAME_START");
278
279 // If process frame has not been called (double rate hardware deint), then
280 // we need to start the first 2 performance timers here
281 if (m_openGLPerf)
282 {
284 {
287 }
288 }
289
291
292 // Clear framebuffer
293 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
294 m_openglRender->logDebugMarker(LOC + "CLEAR_START");
295
296 if (!Frame || Frame->m_dummy || m_needFullClear || ((m_openglRender->GetExtraFeatures() & kGLTiled) != 0))
297 {
300 }
301 // Avoid clearing the framebuffer if it will be entirely overwritten by video
302 else if (!VideoIsFullScreen())
303 {
304 if (IsEmbedding())
305 {
306 // use MythRenderOpenGL rendering as it will clear to the appropriate 'black level'
308 }
309 else
310 {
311 // in the vast majority of cases it is significantly quicker to just
312 // clear the unused portions of the screen
313 QRegion toclear = GetBoundingRegion();
314 for (const auto& rect : std::as_const(toclear))
316 }
317 }
318
319 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
320 m_openglRender->logDebugMarker(LOC + "CLEAR_END");
321
322 // Time framebuffer clearing
323 if (m_openGLPerf)
325
326 // Render
328
329 // Time rendering
330 if (m_openGLPerf)
332
333 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
334 m_openglRender->logDebugMarker(LOC + "RENDER_FRAME_END");
335}
336
338{
339 // Flush and time
341 if (m_openGLPerf)
343}
344
346{
347 if (!m_openglRender || IsErrored())
348 return;
349
351
352 if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
354
356
357 if (m_openGLPerf)
358 {
359 // Time buffer swap and log
360 // Results will normally be available on the next pass - and we will typically
361 // test every other frame as a result to avoid blocking in the driver.
362 // With the default of averaging over 30 samples this should give a 30 sample
363 // average over 60 frames
366 }
367
369}
370
373QStringList MythVideoOutputOpenGL::GetAllowedRenderers(MythRenderOpenGL *Render, MythCodecID CodecId, QSize /*VideoDim*/)
374{
375 QStringList allowed;
376 if (!Render)
377 return allowed;
378
379 if (codec_sw_copy(CodecId))
380 {
381 allowed << "opengl" << "opengl-yv12";
382 return allowed;
383 }
384
385 if (auto format = FrameTypeForCodec(CodecId); FMT_NONE != format)
386 {
388 if (MythOpenGLInterop::GetTypes(Render, supported); supported.find(format) != supported.cend())
389 allowed << "opengl-hw";
390 }
391 return allowed;
392}
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