[vlc-devel] RFC: OpenGL filter design overview
Alexandre Janniaux
ajanni at videolabs.io
Thu Jan 28 11:06:12 UTC 2021
Hi,
A little heads up on the RFC:
1/, 2/, 7/ have been merged.
I've also changed my mind for something simpler on 4/.
Instead of exposing an API + vtable struct, we only forward
the correct pointers through the get_proc_address mechanism,
and we ensure that each implementation is working with the
same behaviour as EGL_KHR_get_all_proc_address.
It avoids the controversial addition of an opaque pointer to
the vlc_gl_t interface, allowing a better ABI compatibility
and less confusion, and greatly simplifies the final patchset.
The patchset is coming and will fix 4/ and 5/ at the same time.
The next step will be offscreen providers for OpenGL.
The patchset for this is still a bit incomplete, regarding
output format compatibility, so it might need improvement after
review.
Regards,
--
Alexandre Janniaux
Videolabs
On Sat, Aug 29, 2020 at 07:58:55PM +0200, Alexandre Janniaux wrote:
> Hi,
>
> The following mail is here to describe the work we've done
> internally at Videolabs regarding the OpenGL refactor and
> introduction of OpenGL filters.
>
> This summary encompass part of my work, but also part of the
> work of Maxime Meisson and Romain Vimont.
>
> The whole project has been separated into multiple steps.
> Some of them have already been merged, sometimes with issues
> that other parts are really meant to solve in the long term,
> and the rest of them are starting to reach a level of stability
> which will allow us to submit them on the mailing list.
>
> Though the work is globally thoroughly and meticulously tested
> on many different platforms it involves (which is basically
> «what VLC supports»), there have been pain points and untested
> code path from the refactoring parts of all this work. Thus, we
> are also exploring ways to test all those parts correctly in an
> automated way on all those platforms too.
>
> For convenience, I splitted this summary into different axis,
> each of which has first the list of goals and then a short
> text digging more into the details.
>
> 1/ Preliminary refactor in OpenGL (merged)
>
> - Make import and sampling separated from the opengl video output code
> so as to reuse it elsewhere, and in particular between filters.
> - Split renderer from vout code, the vout display is mostly in charge of
> setting up the rendering environnment and handle additional queries
> that we add in the end like format change.
> - the format change support is not merged yet.
> - Make core OpenGL client code into a reusable library `libvlc_opengl`
> and `libvlc_opengles`.
>
> This is mainly a step towards the cleaning and clear separation of
> everything that has been introduced in 3.0 regarding OpenGL, while
> allowing new features (libplacebo upscaling for example) to start
> being experimented.
>
>
> 2/ Introduce `opengl filter` capability
>
> - New pipeline taylored only for OpenGL code, with a single OpenGL
> context, potentially multiple framebuffer.
> - Provide a more open design scope for high performance pipeline
> without copies between stages, especially regarding blending.
> - Easier to reuse pieces in different location, like tonemappers,
> encoders, converters... We use it in particular in MediaCodec
> encoder in a different work to fit the encoder within the
> current state of the push model, in OpenGL display obviously,
> and in the `filter_chain` (see latter points).
> - Output can be directly redirected to a framebuffer taylored for
> display/encoder or a framebuffer with multisampling enabled
> and MSAA resolution is automatically done if needed.
> - Independance on the design of video context / decoder device and
> current other rework in the core, which makes it much easier to
> develop in parallel, and much less code to write for a filter,
> while fitting the resource model of OpenGL.
>
> As the capability exposed in this axis is different to `video context`,
> it does not provide the capability to be run in the usual filter_chain
> pipeline but this will be tackled later (6/).
>
> The main goal of this axis is to refactor the drawing code into steps
> and being able to compose it, while taking care only of the OpenGL
> parts (DMABuf, EGLImage, vaapi picture, etc are only textures within
> the OpenGL resource model, and the link between them is tied by the
> opengl interop introduced in the first part).
>
>
> 3/ OpenGL offscreen provider
>
> - New capability for OpenGL provider: `opengl offscreen` for OpenGL and
> `opengl es2 offscreen` for OpenGL ES 2. This is a capability for
> picture buffer producer, splitting the buffer management and the
> rendering itself, much like OpenGL in general.
> - Path leading to `filter_t` capable of running OpenGL pipeline,
> without taking care of the details regarding how OpenGL is
> provided. This is not entirely true given how OpenGL linking is
> done currently but will be with latter work.
> - Change the `gl->swap` prototype to return a `picture_t *`,
> non-offscreen implementation are returning NULL.
> - This is reusable for filters, but also for tests, tonemapper, etc.
>
> The different OpenGL offscreen providers are generating pictures
> at each `swap`, which are bound to the provider `video context`
> and probably tied to a `picture_context_t` describing its opaque
> content. During the design, it was expected that `decoder device`
> would give the correct clue regarding which implementation should
> be used when calling for `any` provider.
>
> This axis has some design flaws regarding the `swap` function. In
> particular `swap` means we can still draw, because the context is
> still active and it must have setup a new buffer, so it needs at least
> two buffers (if we can provide the filters with the number of picture
> they must allocate, it would be this number + 1). A better design scope
> has not really be explored, but it could be replaced by some matching
> `BeginPicture()` and `EndPicture()` calls for example.
>
> It has been established this way to quickly develop the different
> provider implementation, including today:
> - Android surfacetexture
> - EGL pixel buffer (doing CPU <-> GPU transfert)
> - EGL GBM buffers
> - iOS CVPixelBuffer buffers through EAGL
> - MacOSX CVPixelBuffer buffers through CGL
>
> EGL pixel buffer would still work on Windows but wouldn't be a
> correct high performance solution, but it could be replaced either
> by EGL angle implementation or NVidia / AMD specific interop API
> to share the buffer between D3D and OpenGL.
>
> The WASM implementation is almost done too, given that the `opengl`
> implementation already follows the same building blocks as this
> construction, meaning sending `ImageBitmap` objects (towards either
> the canvas that will display it or the future `opengl interop` that
> will bind it to an OpenGL texture).
>
> All those implementations makes it quite compatible with every
> display we have and allows a clear separation between the filter
> that provides the features and the `opengl offscreen` provider
> that provides the platform integration bits.
>
>
> 4/ Rework OpenGL to link OpenGL in providers
>
> - Currently, OpenGL providers are linking the provider libraries like
> EGL, GLX, or CoreVideo but OpenGL is already sometimes needed in
> those kind of modules. But in the general case, OpenGL / OpenGL ES
> must be linked to the clients modules, using the VLC OpenGL vtable
> because they need to load it themselves and it's not always done in
> a dynamic way.
> - Instead, link OpenGL/ES to the provider modules. In particular, on
> Apple systems, it allows to avoid linking OpenGL framework to every
> filters, and on other systems it allows removing the OpenGL
> dependency from `libvlc_opengl` and `libvlc_opengles`.
> - Enable automatic testings of shaders, even though they would be
> generated dynamically during runtime, thanks to mocked OpenGL
> virtual table.
>
> This part is also fixing the current issues on Windows where the
> functions are dynamically loaded through WGL and not found instead of
> being dynamically linked, and makes the filters more independant of
> OpenGL, the last pain point being the includes themselves which should
> either be generated from Khronos repository or at least replaced by
> Khronos generic includes whenever possible.
>
>
> 5/ Handle OpenGL/ES at runtime
>
> - Merge both `libvlc_opengl` and `libvlc_opengles` in a single runtime
> and exposes the difference through a runtime parameter.
> - No need to build filters once for OpenGL and once for OpenGL ES.
> - Continue on the path of dynamic generation of shaders according to
> GLSL version, kind and capabilities, for better performance shaders.
>
> This can have some «unwanted» side effects like forcing to compile
> some OpenGL provider module twice because they should link and provide
> both OpenGL and OpenGL ES, but it will avoid compiling the filter
> modules twice so it's still a win.
>
> 6/ Add a filter_t module `opengl`
>
> - The module is able to receive a list of OpenGL filters and execute
> them in a single pipeline.
> - Uses the previous work on filters, interop, samplers and OpenGL
> offscreen to link the OpenGL pipeline with the `filter_t` pipeline.
> - Exposes a first "user" but non-friendly way to run the filters, but it
> is OpenGL-centered and is not adding the correct filters
> automatically in the pipeline. It starts fixing the flaws from 2/
> but needs what follow to fully implement the OpenGL pipeline in a
> transparent way.
> - As a `filter_t`, it can be used everywhere a `filter_t` is possible.
>
> This is the first step towards OpenGL filters in general, though
> still primitive at this stage since OpenGL filters need to be
> specified in a non-direct way in comparison with usual filters,
> basically meaning for example:
>
> --video-filter=opengl{filters=adjust}
>
> However, this brings a reusable component for other filters which
> will be able to expose themselves as an usual `filter_t` without
> this alienating syntax, and this filter is actually «more powerful»
> in this case since it could be able to do things like adjust and
> logo filters without additional copies.
>
> We didn't explore the design scope for a different filter_t pipeline
> that would be able to automatically gather filters that don't need
> a copy since it would probably have a much bigger toll on
> architectural changes.
>
>
> 7/ Add pf_close / rework virtual table for `filter_t`
>
> - Encompass the `filter_t` implementation as an object, like other
> parts of the pipeline (see `vout_window_t` for instance) instead of
> as a module.
> - Enable wrapping a `filter_t` into another in a simple way: you can
> open any `filter_t` implementation in the Open of your module to
> provide a specialization of a specified filter.
>
> This is basically the additional missing building block to use the
> previously defined `opengl` filter to expose a `video filter`
> capability from OpenGL filters, like we describe in the next axis.
>
>
> 8/ Exposes OpenGL filters as `filter_t` through the `opengl` filter_t
> module
>
> - Add the `video filter` capability in OpenGL filters modules, whose
> `Activate` function will parse the filter parameters, define the
> VLC variable `opengl-filter` and open the `opengl` filter to run
> the `opengl filter` implementation.
> - Allows to expose some modules to the pipeline in an automatic way,
> and other modules for internal purpose.
> - This execution mode use OpenGL offscreen implementation to export the
> rendered image, with the offscreen video context, thus matching the
> push model completely, and is not a barrier for any future filter
> pipelining.
>
> We currently exposed `deinterlace` (`yadif` and `yadif2x`) and `adjust`
> filters with great success and few complexity, while allowing to parse
> the module option config like every other modules. Thanks to the GSoC
> program student Vatsin, we also have filters like `zoom` which can also
> showcase the usage of the mouse, though it has not been added yet.
>
> This also, and mainly, allows to expose the OpenGL filters like any
> other filters within the interface, without changes to the interfaces.
>
>
> 9/ Add support for plane filters
>
> - Allow to filter picture planes separately instead of filtering the whole
> picture at once (typically for deinterlace filters).
> - If a filter sets the "filter_plane" flag, then the filter engine
> generates one output texture per plane and calls the filter once for each
> plane.
> - The sampler of the following (normal) filter will take care of chroma
> conversion to each resulting pixels as a single RGBA vector.
>
> This is a building block for the yadif/2x filter we made, which allows to
> reduce bandwidth and integrate with following filters through vlc_gl_sampler.
> It mainly bends the sampler object which usually gather the different input
> textures behind a single `vlc_texture` call, and is the only current way to
> process non-RGB input into non-RGB output.
>
> The thread is a bit dense, but I hope it's also short-enough considering
> the real size of the work, which mostly started one year ago with the
> points 2/ and 3/.
>
> Feel free to provide any feedback regarding points that might have been
> left unaddressed or miss-addressed, or request more details regarding
> each axis. I'd invite you to open one subthread from the main topic for
> each point you'd want to comment though, so as to ease the discussion
> process and avoid confusion.
>
> I hope it fills the need for a global picture over this work.
>
> Regards,
> --
> Alexandre Janniaux
> Videolabs
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list