Linux Video Renderer vsync issues because of EGL
#1
Since a few months ago, XBMC is able to run on Linux systems using the Android GPU drivers for EGL support via libhybris, using a (unsupported in the main xbmc repo) EGLNativeTypeHybris plugin: https://www.youtube.com/watch?v=MUorE09cC-4

More recently, we have also successfully tried XBMC running on wayland (no additions to the main repo), where wayland is running thanks to libhybris: https://www.youtube.com/watch?v=KYymcNoGmqQ and https://www.youtube.com/watch?v=DRBzOpxEaiU This is more desirable since everything is in the main repo already Smile


There is one issue when using libhybris (either wayland or the EGLNativeTypeHybris plugin): there is a tearing appearing *sometimes - quite often - maybe depending of how much actions is in the scene* in the top right corner - always the same place, always the same size - it's a square almost 1/4 of the screen.
You can see it around minute 1:30 in the first wayland video - there is a trembling in that quarter of the screen. This issue is present both in EGLNativeTypeHybris and wayland - so the culprit is probably somewhere between libhybris egl and xbmc video renderer - maybe not getting the right refresh rate from libhybris, maybe doing it too often and overwriting some buffers - in the video above with wayland you can see xbmc reporting 600Hz refresh rate - or maybe hybris tries that with the movie too - no idea.

One of the contributors had a workaround for that issue in the EGLNativeTypeHybris plugin - see https://github.com/mihailescu2m/xbmc/blo...is.cpp#L92
I can't say I have a good idea what exactly is happening, but I would say he's made a thread (though using hybris does not require you to use a separate thread) where he is calling a paintEvent.set() in addition to the normal hybris display code (no idea how these events work in XBMC Sad )

Unfortunately... newer versions of libhybris changed the API for how buffers are handling - and instead of having to call lockFrontBuffer -> prepare and set buffers -> unlockFrontBuffer like in the code above (ahead of the paintEvent) - now there is a callback that is executed by libhybris. We have already adapted EGLNativeTypeHybris to that - this is the commit for the new libhybris API:
https://github.com/Owersun/xbmc/commit/2...a5f06b96b9

In there you basically see that there is no more thread doing the painting, but it's subclassing HWComposerNativeWindow and moving the - prepare and set buffers - code in libhybris HWComposerNativeWindow::present virtual function.
You see that now there is no more thread calling the paintEvent like in the previous hack, and the tearing is back ... (both in wayland and EGLNativeTypeHybris using the new hybris API).

Now, here's a fun thing - if you press TAB when playing and get the menu overlay on top of the movie - the tearing is gone (see again the video at the end where there is the menu on top ... it's really smooth then!). This leads me to believe that indeed in full-screen video mode the renderer has the wrong refresh rate - while in full-screen egl application mode the refresh is OK... see also second wayland video... i was not able the see tearing, albeit the window is small...

Maybe someone here with a better understanding of the video renderer and the egl windows can understand what's going on and offer some help...
Is there a way to cap the refresh rate of the video renderer? (either up or down?)
Why is this happening only on full screen video mode, and when the menu is shown then it's not tearing anymore? Is the EGL window that shows the menu somehow fiddling with the refresh rate?
Is there a different "mode" flag being passed around for full-screen and windowed? How could I try the "windowed" mode - but a window as big as the screen... Is there a way to call that paint event from another part of the code?
How could I try a hack to simulate an invisible menu-like overlay?

For completeness... the tearing is gone only when the menu was shown, when having the overlay with the movie info at the bottom like at 1:26 there as still tearing - any idea why that would be (probably the video is still in FULL-SCREEN mode)?

Thanks!
Reply
#2
So, I found a workaround. The flicker is gone, but it is a very ugly workaround....
Maybe someone can explain to me why this workaround works and how to make a proper fix.

I first tried to check vsync settings - there is no SetVSync in wayland. I ended up putting a big Sleep() in the video renderer Present function - I slowed rendering down to 1fps, and still that 1fps would sometime flicker!

So then I tried different settings for dirtyregions. Only 0 and 3 worked... 1 and 2 would crash xbmc on wayland on start.
I had hopes 0 will fix it ... but no.
Finally, I enabled visualizedirtyregions. Well, the flicker was gone!
So I ended up changing the color of the dirtyregions to invisible.
Now there is no more flicker.... CPU usage is not increased, but fps gets down a lot when showing the menu on top of a movie.
I can probably find a fixed or max number of dirty regions for which to do CGUITexture:Big GrinrawQuad(*i, 0x00000000); such that I can improve performance....

So please, anyone can understand what is going on and how to properly fix this?
Reply
#3
I have found a fix for this issue...

Code:
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index 212ed27..a01e3cb 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1055,9 +1055,9 @@ void CXBMCRenderManager::PrepareNextRender()

   /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
   bool next;
-  if(g_graphicsContext.IsFullScreenVideo())
-    next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
-  else
+//  if(g_graphicsContext.IsFullScreenVideo())
+//    next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
+//  else
     next = (m_Queue[idx].timestamp <= clocktime + frametime);

   if (next)

Is there an official reason why fullscreen video is handled differently?
Reply
#4
(2014-08-25, 16:07)memeka Wrote: Is there an official reason why fullscreen video is handled differently?

Yes, when playing video in fullscreen mode, we render at video fps rate, otherwise at refresh rate fps.
Reply
#5
Well... my setup is more complicated: XBMC runs under wayland. Wayland uses libhybris and android drivers.
Something does not go through properly, but I can't see clearly what (probably refresh rate).
EGL works very nice... GLES works wonderful ... shaders work... video decoding even (in linux with android media codec via hybris)...
This was literally the only issue. Refresh rate in wayland is reported in xbmc at 600Hz ... so probably the issue is with the refresh rate ...
But still I can't see why this happens since EGL for example works fine.
Reply
#6
What fps (measured) do you observe? The render loop is supposed to be limited by SwapBuffers, VSync should make sure that tearing is avoided.
Reply
#7
When running not fullscreen video the render thread typically blocks in SwapBuffers. When playing fullscreen video the thread waits in RenderManager::WaitPresentTime.
Reply
#8
I guess then SwapBuffers is ok, but waiting in WaitPresentTime is not ... if the waiting time is MAXPRESENTDELAY. With wait time of frametime is ok.
Maybe in that extra-wait the buffers get changed by libhybris...
I am really not familiar with EGL inner-workings Big Grin
Reply
#9
In order to track this further down I would investigate why tearing happens at all. AFAIK wayland is designed to avoid it. Makes me think something goes wrong inside the lib.

There may indeed an issue with timing in regard to a/v sync. Currently we assume double buffering when calculating the presentation timestamps.

You could further optimize your system by implementing some methods for video reference clock. I.e. on GLX systems this is synchronized to vblank and WaitPresentTIme would return right after a vblank.
Reply
#10
This is not an issue with wayland.
The same was happening when using directly EGL under libhybris: https://github.com/mihailescu2m/xbmc/blo...Hybris.cpp
And I don't know enough about libhybris.
FPS is great > I mean interface is 60fps (with Ace skin, which is not light); movie was showing ~24fps; movie playing with interface overlay >50fps.
Reply
#11
If you activate "sync to vblank" there can't be any tearing unless the driver has an issue.

If fps rises that high with an overlay shows your system does not change refresh rate to 24hz right? Does your driver has a feature like adaptive vsync? Those type of features turn off vsync if fps drops below refresh rate. This is certainly not what you want here.
Reply
#12
The Android driver that is used by libhybris probably yes - since xbmc in android is working fine.
Reply

Logout Mark Read Team Forum Stats Members Help
Video Renderer vsync issues because of EGL0