From 65979986a923a8f08019b257c3fe72cd5e8ecf68 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Thu, 14 Sep 2017 08:04:55 +0200 Subject: vo_opengl: refactor into vo_gpu This is done in several steps: 1. refactor MPGLContext -> struct ra_ctx 2. move GL-specific stuff in vo_opengl into opengl/context.c 3. generalize context creation to support other APIs, and add --gpu-api 4. rename all of the --opengl- options that are no longer opengl-specific 5. move all of the stuff from opengl/* that isn't GL-specific into gpu/ (note: opengl/gl_utils.h became opengl/utils.h) 6. rename vo_opengl to vo_gpu 7. to handle window screenshots, the short-term approach was to just add it to ra_swchain_fns. Long term (and for vulkan) this has to be moved to ra itself (and vo_gpu altered to compensate), but this was a stop-gap measure to prevent this commit from getting too big 8. move ra->fns->flush to ra_gl_ctx instead 9. some other minor changes that I've probably already forgotten Note: This is one half of a major refactor, the other half of which is provided by rossy's following commit. This commit enables support for all linux platforms, while his version enables support for all non-linux platforms. Note 2: vo_opengl_cb.c also re-uses ra_gl_ctx so it benefits from the --opengl- options like --opengl-early-flush, --opengl-finish etc. Should be a strict superset of the old functionality. Disclaimer: Since I have no way of compiling mpv on all platforms, some of these ports were done blindly. Specifically, the blind ports included context_mali_fbdev.c and context_rpi.c. Since they're both based on egl_helpers, the port should have gone smoothly without any major changes required. But if somebody complains about a compile error on those platforms (assuming anybody actually uses them), you know where to complain. --- DOCS/interface-changes.rst | 16 + DOCS/man/mpv.rst | 6 +- DOCS/man/options.rst | 170 +- DOCS/man/vo.rst | 33 +- DOCS/mplayer-changes.rst | 6 +- etc/builtin.conf | 6 +- etc/mpv.conf | 4 +- options/options.c | 11 +- options/options.h | 1 + player/main.c | 17 - video/out/gpu/context.c | 186 ++ video/out/gpu/context.h | 95 + video/out/gpu/hwdec.c | 239 +++ video/out/gpu/hwdec.h | 130 ++ video/out/gpu/lcms.c | 531 +++++ video/out/gpu/lcms.h | 43 + video/out/gpu/osd.c | 367 ++++ video/out/gpu/osd.h | 25 + video/out/gpu/ra.c | 327 +++ video/out/gpu/ra.h | 488 +++++ video/out/gpu/shader_cache.c | 954 +++++++++ video/out/gpu/shader_cache.h | 56 + video/out/gpu/user_shaders.c | 452 ++++ video/out/gpu/user_shaders.h | 98 + video/out/gpu/utils.c | 372 ++++ video/out/gpu/utils.h | 120 ++ video/out/gpu/video.c | 3809 ++++++++++++++++++++++++++++++++ video/out/gpu/video.h | 194 ++ video/out/gpu/video_shaders.c | 872 ++++++++ video/out/gpu/video_shaders.h | 56 + video/out/opengl/common.h | 4 +- video/out/opengl/context.c | 446 ++-- video/out/opengl/context.h | 152 +- video/out/opengl/context_cocoa.c | 2 +- video/out/opengl/context_drm_egl.c | 194 +- video/out/opengl/context_glx.c | 376 ++++ video/out/opengl/context_mali_fbdev.c | 58 +- video/out/opengl/context_rpi.c | 84 +- video/out/opengl/context_vdpau.c | 202 +- video/out/opengl/context_wayland.c | 74 +- video/out/opengl/context_x11.c | 358 ---- video/out/opengl/context_x11egl.c | 84 +- video/out/opengl/egl_helpers.c | 114 +- video/out/opengl/egl_helpers.h | 19 +- video/out/opengl/formats.h | 1 - video/out/opengl/gl_utils.c | 291 --- video/out/opengl/gl_utils.h | 56 - video/out/opengl/hwdec.c | 239 --- video/out/opengl/hwdec.h | 130 -- video/out/opengl/hwdec_cuda.c | 3 +- video/out/opengl/hwdec_ios.m | 2 +- video/out/opengl/hwdec_osx.c | 2 +- video/out/opengl/hwdec_rpi.c | 2 +- video/out/opengl/hwdec_vaegl.c | 4 +- video/out/opengl/hwdec_vaglx.c | 5 +- video/out/opengl/hwdec_vdpau.c | 2 +- video/out/opengl/lcms.c | 531 ----- video/out/opengl/lcms.h | 43 - video/out/opengl/osd.c | 367 ---- video/out/opengl/osd.h | 25 - video/out/opengl/ra.c | 327 --- video/out/opengl/ra.h | 491 ----- video/out/opengl/ra_gl.c | 7 - video/out/opengl/ra_gl.h | 3 +- video/out/opengl/shader_cache.c | 955 --------- video/out/opengl/shader_cache.h | 56 - video/out/opengl/user_shaders.c | 452 ---- video/out/opengl/user_shaders.h | 98 - video/out/opengl/utils.c | 524 ++--- video/out/opengl/utils.h | 151 +- video/out/opengl/video.c | 3813 --------------------------------- video/out/opengl/video.h | 195 -- video/out/opengl/video_shaders.c | 872 -------- video/out/opengl/video_shaders.h | 56 - video/out/vo.c | 6 +- video/out/vo_gpu.c | 385 ++++ video/out/vo_opengl.c | 470 ---- video/out/vo_opengl_cb.c | 53 +- video/out/vo_rpi.c | 2 +- wscript | 13 +- wscript_build.py | 47 +- 81 files changed, 11414 insertions(+), 11116 deletions(-) create mode 100644 video/out/gpu/context.c create mode 100644 video/out/gpu/context.h create mode 100644 video/out/gpu/hwdec.c create mode 100644 video/out/gpu/hwdec.h create mode 100644 video/out/gpu/lcms.c create mode 100644 video/out/gpu/lcms.h create mode 100644 video/out/gpu/osd.c create mode 100644 video/out/gpu/osd.h create mode 100644 video/out/gpu/ra.c create mode 100644 video/out/gpu/ra.h create mode 100644 video/out/gpu/shader_cache.c create mode 100644 video/out/gpu/shader_cache.h create mode 100644 video/out/gpu/user_shaders.c create mode 100644 video/out/gpu/user_shaders.h create mode 100644 video/out/gpu/utils.c create mode 100644 video/out/gpu/utils.h create mode 100644 video/out/gpu/video.c create mode 100644 video/out/gpu/video.h create mode 100644 video/out/gpu/video_shaders.c create mode 100644 video/out/gpu/video_shaders.h create mode 100644 video/out/opengl/context_glx.c delete mode 100644 video/out/opengl/context_x11.c delete mode 100644 video/out/opengl/gl_utils.c delete mode 100644 video/out/opengl/gl_utils.h delete mode 100644 video/out/opengl/hwdec.c delete mode 100644 video/out/opengl/hwdec.h delete mode 100644 video/out/opengl/lcms.c delete mode 100644 video/out/opengl/lcms.h delete mode 100644 video/out/opengl/osd.c delete mode 100644 video/out/opengl/osd.h delete mode 100644 video/out/opengl/ra.c delete mode 100644 video/out/opengl/ra.h delete mode 100644 video/out/opengl/shader_cache.c delete mode 100644 video/out/opengl/shader_cache.h delete mode 100644 video/out/opengl/user_shaders.c delete mode 100644 video/out/opengl/user_shaders.h delete mode 100644 video/out/opengl/video.c delete mode 100644 video/out/opengl/video.h delete mode 100644 video/out/opengl/video_shaders.c delete mode 100644 video/out/opengl/video_shaders.h create mode 100644 video/out/vo_gpu.c delete mode 100644 video/out/vo_opengl.c diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 656a5d204f..8d8870d81d 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -22,6 +22,22 @@ Interface changes --- mpv 0.28.0 --- - drop previously deprecated --heartbeat-cmd and --heartbeat--interval options + - rename --vo=opengl to --vo=gpu + - rename --opengl-backend to --gpu-context + - rename --opengl-shaders to --glsl-shaders + - rename --opengl-shader-cache-dir to --gpu-shader-cache-dir + - rename --opengl-tex-pad-x/y to --gpu-tex-pad-x/y + - rename --opengl-fbo-format to --fbo-format + - rename --opengl-gamma to --gamma-factor + - rename --opengl-debug to --gpu-debug + - rename --opengl-sw to --gpu-sw + - rename --opengl-vsync-fences to --swapchain-depth, and the interpretation + slightly changed. Now defaults to 3. + - rename the built-in profile `opengl-hq` to `gpu-hq` + - the semantics of --opengl-es=yes are slightly changed -> now requires GLES + - remove the (deprecated) alias --gpu-context=drm-egl + - remove the (deprecated) --vo=opengl-hq + - remove --opengl-es=force2 (use --opengl-es=yes --opengl-restrict=300) --- mpv 0.27.0 --- - drop previously deprecated --field-dominance option - drop previously deprecated "osd" command diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 7202e326e7..a307cc2ff2 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -510,8 +510,8 @@ setting them to *no*. Even suboptions can be specified in this way. :: - # Use opengl video output by default. - vo=opengl + # Use GPU-accelerated video output by default. + vo=gpu # Use quotes for text that can contain spaces: status-msg="Time: ${time-pos}" @@ -582,7 +582,7 @@ profile name ``default`` to continue with normal options. [slow] profile-desc="some profile name" # reference a builtin profile - profile=opengl-hq + profile=gpu-hq [fast] vo=vdpau diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index fa2f676190..4a880fb72c 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -667,29 +667,29 @@ Video :auto: enable best hw decoder (see below) :yes: exactly the same as ``auto`` :auto-copy: enable best hw decoder with copy-back (see below) - :vdpau: requires ``--vo=vdpau`` or ``--vo=opengl`` (Linux only) + :vdpau: requires ``--vo=gpu`` or ``--vo=vdpau`` (Linux only) :vdpau-copy: copies video back into system RAM (Linux with some GPUs only) - :vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux only) + :vaapi: requires ``--vo=gpu`` or ``--vo=vaapi`` (Linux only) :vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only) - :videotoolbox: requires ``--vo=opengl`` (OS X 10.8 and up), + :videotoolbox: requires ``--vo=gpu`` (OS X 10.8 and up), or ``--vo=opengl-cb`` (iOS 9.0 and up) :videotoolbox-copy: copies video back into system RAM (OS X 10.8 or iOS 9.0 and up) - :dxva2: requires ``--vo=opengl`` with ``--opengl-backend=angle`` or - ``--opengl-backend=dxinterop`` (Windows only) + :dxva2: requires ``--vo=gpu`` with ``--gpu-context=angle`` or + ``--gpu-context=dxinterop`` (Windows only) :dxva2-copy: copies video back to system RAM (Windows only) - :d3d11va: requires ``--vo=opengl`` with ``--opengl-backend=angle`` + :d3d11va: requires ``--vo=gpu`` with ``--gpu-context=angle`` (Windows 8+ only) :d3d11va-copy: copies video back to system RAM (Windows 8+ only) :mediacodec: copies video back to system RAM (Android only) - :rpi: requires ``--vo=opengl`` (Raspberry Pi only - default if available) + :rpi: requires ``--vo=gpu`` (Raspberry Pi only - default if available) :rpi-copy: copies video back to system RAM (Raspberry Pi only) - :cuda: requires ``--vo=opengl`` (Any platform CUDA is available) + :cuda: requires ``--vo=gpu`` (Any platform CUDA is available) :cuda-copy: copies video back to system RAM (Any platform CUDA is available) :crystalhd: copies video back to system RAM (Any platform supported by hardware) ``auto`` tries to automatically enable hardware decoding using the first available method. This still depends what VO you are using. For example, - if you are not using ``--vo=vdpau`` or ``--vo=opengl``, vdpau decoding will + if you are not using ``--vo=gpu`` or ``--vo=vdpau``, vdpau decoding will never be enabled. Also note that if the first found method doesn't actually work, it will always fall back to software decoding, instead of trying the next method (might matter on some Linux systems). @@ -701,10 +701,10 @@ Video guaranteed to incur no additional loss compared to software decoding, and will allow CPU processing with video filters. - The ``vaapi`` mode, if used with ``--vo=opengl``, requires Mesa 11 and most + The ``vaapi`` mode, if used with ``--vo=gpu``, requires Mesa 11 and most likely works with Intel GPUs only. It also requires the opengl EGL backend (automatically used if available). You can also try the old GLX backend by - forcing it with ``--opengl-backend=x11``, but the vaapi/GLX interop is + forcing it with ``--gpu-context=x11``, but the vaapi/GLX interop is said to be slower than ``vaapi-copy``. The ``cuda`` and ``cuda-copy`` modes provides deinterlacing in the decoder @@ -712,7 +712,7 @@ Video output path. To use this deinterlacing you must pass the option: ``vd-lavc-o=deint=[weave|bob|adaptive]``. Pass ``weave`` (or leave the option unset) to not attempt any - deinterlacing. ``cuda`` should always be preferred unless the ``opengl`` + deinterlacing. ``cuda`` should always be preferred unless the ``gpu`` vo is not being used or filters are required. Most video filters will not work with hardware decoding as they are @@ -739,8 +739,8 @@ Video be some loss, or even blatantly incorrect results. In some cases, RGB conversion is forced, which means the RGB conversion - is performed by the hardware decoding API, instead of the OpenGL code - used by ``--vo=opengl``. This means certain colorspaces may not display + is performed by the hardware decoding API, instead of the shaders + used by ``--vo=gpu``. This means certain colorspaces may not display correctly, and certain filtering (such as debanding) cannot be applied in an ideal way. This will also usually force the use of low quality chroma scalers instead of the one specified by ``--cscale``. In other @@ -772,7 +772,7 @@ Video completely ordinary video sources. ``rpi`` always uses the hardware overlay renderer, even with - ``--vo=opengl``. + ``--vo=gpu``. ``cuda`` should be safe, but it has been reported to corrupt the timestamps causing glitched, flashing frames on some files. It can also @@ -800,13 +800,13 @@ Video the first thing you should try is disabling it. ``--opengl-hwdec-interop=`` - This is useful for the ``opengl`` and ``opengl-cb`` VOs for creating the + This is useful for the ``gpu`` and ``opengl-cb`` VOs for creating the hardware decoding OpenGL interop context, but without actually enabling hardware decoding itself (like ``--hwdec`` does). If set to an empty string (default), the ``--hwdec`` option is used. - For ``opengl``, if set, do not create the interop context on demand, but + For ``gpu``, if set, do not create the interop context on demand, but when the VO is created. For ``opengl-cb``, if set, load the interop context as soon as the OpenGL @@ -1049,7 +1049,7 @@ Video This can speed up video upload, and may help with large resolutions or slow hardware. This works only with the following VOs: - - ``opengl``: requires at least OpenGL 4.4. + - ``gpu``: requires at least OpenGL 4.4. (In particular, this can't be made work with ``opengl-cb``.) @@ -2402,8 +2402,8 @@ Window ``--force-rgba-osd-rendering`` Change how some video outputs render the OSD and text subtitles. This does not change appearance of the subtitles and only has performance - implications. For VOs which support native ASS rendering (like ``vdpau``, - ``opengl``, ``direct3d``), this can be slightly faster or slower, + implications. For VOs which support native ASS rendering (like ``gpu``, + ``vdpau``, ``direct3d``), this can be slightly faster or slower, depending on GPU drivers and hardware. For other VOs, this just makes rendering slower. @@ -3903,10 +3903,10 @@ ALSA audio output options ALSA device). -OpenGL renderer options +GPU renderer options ----------------------- -The following video options are currently all specific to ``--vo=opengl`` and +The following video options are currently all specific to ``--vo=gpu`` and ``--vo=opengl-cb`` only, which are the only VOs that implement them. ``--scale=`` @@ -3917,7 +3917,7 @@ The following video options are currently all specific to ``--vo=opengl`` and is the default for compatibility reasons. ``spline36`` - Mid quality and speed. This is the default when using ``opengl-hq``. + Mid quality and speed. This is the default when using ``gpu-hq``. ``lanczos`` Lanczos scaling. Provides mid quality and speed. Generally worse than @@ -4080,7 +4080,7 @@ The following video options are currently all specific to ``--vo=opengl`` and ``--linear-scaling`` Scale in linear light. It should only be used with a - ``--opengl-fbo-format`` that has at least 16 bit precision. This option + ``--fbo-format`` that has at least 16 bit precision. This option has no effect on HDR content. ``--correct-downscaling`` @@ -4104,7 +4104,7 @@ The following video options are currently all specific to ``--vo=opengl`` and the ``--tscale`` setting. Note that this relies on vsync to work, see ``--opengl-swapinterval`` for - more information. It should also only be used with an ``--opengl-fbo-format`` + more information. It should also only be used with an ``--fbo-format`` that has at least 16 bit precision. ``--interpolation-threshold=<0..1,-1>`` @@ -4168,10 +4168,10 @@ The following video options are currently all specific to ``--vo=opengl`` and ``--temporal-dither`` is in use. 1 (the default) will update on every video frame, 2 on every other frame, etc. -``--opengl-debug`` - Check for OpenGL errors, i.e. call ``glGetError()``. Also, request a - debug OpenGL context (which does nothing with current graphics drivers - as of this writing). +``--gpu-debug`` + Enables GPU debugging. What this means depends on the API type. For OpenGL, + it calls ``glGetError()``, and requests a debug context. For Vulkan, it + enables validation layers. ``--opengl-swapinterval=`` Interval in displayed frames between two buffer swaps. 1 is equivalent to @@ -4184,7 +4184,7 @@ The following video options are currently all specific to ``--vo=opengl`` and results, as can missing or incorrect display FPS information (see ``--display-fps``). -``--opengl-shaders=`` +``--glsl-shaders=`` Custom GLSL hooks. These are a flexible way to add custom fragment shaders, which can be injected at almost arbitrary points in the rendering pipeline, and access all previous intermediate textures. Each use of the option will @@ -4226,7 +4226,7 @@ The following video options are currently all specific to ``--vo=opengl`` and FORMAT (required) The texture format for the samples. Supported texture formats are listed - in debug logging when the ``opengl`` VO is initialized (look for + in debug logging when the ``gpu`` VO is initialized (look for ``Texture formats:``). Usually, this follows OpenGL naming conventions. For example, ``rgb16`` provides 3 channels with normalized 16 bit components. One oddity are float formats: for example, ``rgba16f`` has @@ -4369,8 +4369,8 @@ The following video options are currently all specific to ``--vo=opengl`` and vec2 tex_offset Texture offset introduced by user shaders or options like panscan, video-align-x/y, video-pan-x/y. - Internally, vo_opengl may generate any number of the following textures. - Whenever a texture is rendered and saved by vo_opengl, all of the passes + Internally, vo_gpu may generate any number of the following textures. + Whenever a texture is rendered and saved by vo_gpu, all of the passes that have hooked into it will run, in the order they were added by the user. This is a list of the legal hook points: @@ -4416,8 +4416,8 @@ The following video options are currently all specific to ``--vo=opengl`` and pass. When overwriting a texture marked ``fixed``, the WIDTH, HEIGHT and OFFSET must be left at their default values. -``--opengl-shader=`` - CLI/config file only alias for ``--opengl-shaders-append``. +``--glsl-shader=`` + CLI/config file only alias for ``--glsl-shaders-append``. ``--deband`` Enable the debanding algorithm. This greatly reduces the amount of visible @@ -4470,9 +4470,9 @@ The following video options are currently all specific to ``--vo=opengl`` and ``--scale-blur`` option. ``--opengl-glfinish`` - Call ``glFinish()`` before and after swapping buffers (default: disabled). - Slower, but might improve results when doing framedropping. Can completely - ruin performance. The details depend entirely on the OpenGL driver. + Call ``glFinish()`` before swapping buffers (default: disabled). Slower, + but might improve results when doing framedropping. Can completely ruin + performance. The details depend entirely on the OpenGL driver. ``--opengl-waitvsync`` Call ``glXWaitVideoSyncSGI`` after each buffer swap (default: disabled). @@ -4481,15 +4481,6 @@ The following video options are currently all specific to ``--vo=opengl`` and X11/GLX only. -``--opengl-vsync-fences=`` - Synchronize the CPU to the Nth past frame using the ``GL_ARB_sync`` - extension. A value of 0 disables this behavior (default). A value of 1 - means it will synchronize to the current frame after rendering it. Like - ``--glfinish`` and ``--waitvsync``, this can lower or ruin performance. Its - advantage is that it can span multiple frames, and effectively limit the - number of frames the GPU queues ahead (which also has an influence on - vsync). - ``--opengl-dwmflush=`` Calls ``DwmFlush`` after swapping buffers on Windows (default: auto). It also sets ``SwapInterval(0)`` to ignore the OpenGL timing. Values are: no @@ -4510,7 +4501,7 @@ The following video options are currently all specific to ``--vo=opengl`` and used to select a lower feature level, which is mainly useful for debugging. Note that OpenGL ES 3.0 is only supported at feature level 10_1 or higher. Most extended OpenGL features will not work at lower feature levels - (similar to ``--opengl-dumb-mode``). + (similar to ``--gpu-dumb-mode``). Windows with ANGLE only. @@ -4566,7 +4557,7 @@ The following video options are currently all specific to ``--vo=opengl`` and renderer, though ``--angle-renderer=d3d9`` may give slightly better performance on old hardware. Note that the D3D9 renderer only supports OpenGL ES 2.0, so most extended OpenGL features will not work if this - renderer is selected (similar to ``--opengl-dumb-mode``). + renderer is selected (similar to ``--gpu-dumb-mode``). Windows with ANGLE only. @@ -4587,13 +4578,21 @@ The following video options are currently all specific to ``--vo=opengl`` and OS X only. -``--opengl-sw`` +``--swapchain-depth=`` + Allow up to N in-flight frames. This essentially controls the frame + latency. Increasing the swapchain depth can improve pipelining and prevent + missed vsyncs, but increases visible latency. This option only mandates an + upper limit, the implementation can use a lower latency than requested + internally. A setting of 1 means that the VO will wait for every frame to + become visible before starting to render the next frame. (Default: 3) + +``--gpu-sw`` Continue even if a software renderer is detected. -``--opengl-backend=`` - The value ``auto`` (the default) selects the windowing backend. You can - also pass ``help`` to get a complete list of compiled in backends (sorted - by autoprobe order). +``--gpu-context=`` + The value ``auto`` (the default) selects the GPU context. You can also pass + ``help`` to get a complete list of compiled in backends (sorted by + autoprobe order). auto auto-select (default) @@ -4617,7 +4616,7 @@ The following video options are currently all specific to ``--vo=opengl`` and wayland Wayland/EGL drm - DRM/EGL (``drm-egl`` is a deprecated alias) + DRM/EGL x11egl X11/EGL mali-fbdev @@ -4628,19 +4627,32 @@ The following video options are currently all specific to ``--vo=opengl`` and performance problems), and is for doing experiments only. Will not be used automatically. +``--gpu-api=`` + Controls which type of graphics APIs will be accepted: + + auto + Use any available API (default) + opengl + Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+) + ``--opengl-es=`` - Select whether to use GLES: + Controls which type of OpenGL context will be accepted: + auto + Allow all types of OpenGL (default) yes - Try to prefer ES over Desktop GL - force2 - Try to request a ES 2.0 context (the driver might ignore this) + Only allow GLES no - Try to prefer desktop GL over ES - auto - Use the default for each backend (default) + Only allow desktop/core GL -``--opengl-fbo-format=`` +``--opengl-restrict=`` + Restricts all OpenGL versions above a certain version. Versions are encoded + in hundreds, i.e. OpenGL 4.5 -> 450. As an example, --opengl-restrict=300 + would restrict OpenGL 3.0 and higher, effectively only allowing 2.x + contexts. Note that this only imposes a limit on context creation APIs, the + actual OpenGL context may still have a higher OpenGL version. (Default: 0) + +``--fbo-format=`` Selects the internal format of textures used for FBOs. The format can influence performance and quality of the video output. ``fmt`` can be one of: rgb8, rgb10, rgb10_a2, rgb16, rgb16f, rgb32f, rgba12, rgba16, rgba16f, @@ -4648,10 +4660,10 @@ The following video options are currently all specific to ``--vo=opengl`` and or rgb10_a2 on GLES (e.g. ANGLE), unless GL_EXT_texture_norm16 is available. -``--opengl-gamma=<0.1..2.0>`` - Set a gamma value (default: 1.0). If gamma is adjusted in other ways (like - with the ``--gamma`` option or key bindings and the ``gamma`` property), - the value is multiplied with the other gamma value. +``--gamma-factor=<0.1..2.0>`` + Set an additional raw gamma factor (default: 1.0). If gamma is adjusted in + other ways (like with the ``--gamma`` option or key bindings and the + ``gamma`` property), the value is multiplied with the other gamma value. Recommended values based on the environmental brightness: @@ -4888,7 +4900,7 @@ The following video options are currently all specific to ``--vo=opengl`` and Blend subtitles directly onto upscaled video frames, before interpolation and/or color management (default: no). Enabling this causes subtitles to be affected by ``--icc-profile``, ``--target-prim``, ``--target-trc``, - ``--interpolation``, ``--opengl-gamma`` and ``--post-shader``. It also + ``--interpolation``, ``--gpu-gamma`` and ``--post-shader``. It also increases subtitle performance when using ``--interpolation``. The downside of enabling this is that it restricts subtitles to the visible @@ -4918,7 +4930,7 @@ The following video options are currently all specific to ``--vo=opengl`` and if the video contains alpha information (which is extremely rare). May not be supported on all platforms. If alpha framebuffers are unavailable, it silently falls back on a normal framebuffer. Note that - if you set the ``--opengl-fbo-format`` option to a non-default value, a + if you set the ``--fbo-format`` option to a non-default value, a format with alpha must be specified, or this won't work. This does not work on X11 with EGL and Mesa (freedesktop bug 67676). no @@ -4933,7 +4945,7 @@ The following video options are currently all specific to ``--vo=opengl`` and Color used to draw parts of the mpv window not covered by video. See ``--osd-color`` option how colors are defined. -``--opengl-tex-pad-x``, ``--opengl-tex-pad-y`` +``--gpu-tex-pad-x``, ``--gpu-tex-pad-y`` Enlarge the video source textures by this many pixels. For debugging only (normally textures are sized exactly, but due to hardware decoding interop we may have to deal with additional padding, which can be tested with these @@ -4947,8 +4959,8 @@ The following video options are currently all specific to ``--vo=opengl`` and flipping GL front and backbuffers immediately (i.e. it doesn't call it in display-sync mode). -``--opengl-dumb-mode=`` - This mode is extremely restricted, and will disable most extended OpenGL +``--gpu-dumb-mode=`` + This mode is extremely restricted, and will disable most extended features. That includes high quality scalers and custom shaders! It is intended for hardware that does not support FBOs (including GLES, @@ -4961,18 +4973,16 @@ The following video options are currently all specific to ``--vo=opengl`` and This option might be silently removed in the future. -``--opengl-shader-cache-dir=`` - Store and load compiled GL shaders in this directory. Normally, shader - compilation is very fast, so this is usually not needed. But some GL - implementations (notably ANGLE, the default on Windows) have relatively - slow shader compilation, and can cause startup delays. +``--gpu-shader-cache-dir=`` + Store and load compiled GLSL shaders in this directory. Normally, shader + compilation is very fast, so this is usually not needed. It mostly matters + for GPU APIs that require internally recompiling shaders to other languages, + for example anything based on ANGLE or Vulkan. Enabling this can improve + startup performance on these platforms. NOTE: This is not cleaned automatically, so old, unused cache files may stick around indefinitely. - This option might be silently removed in the future, if ANGLE fixes shader - compilation speed. - ``--cuda-decode-device=`` Choose the GPU device used for decoding when using the ``cuda`` hwdec. diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index 1552b217cb..84b3a6a9d9 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -14,7 +14,7 @@ in the list. See ``--vo=help`` for a list of compiled-in video output drivers. - The recommended output driver is ``--vo=opengl``, which is the default. All + The recommended output driver is ``--vo=gpu``, which is the default. All other drivers are for compatibility or special purposes. If the default does not work, it will fallback to other drivers (in the same order as listed by ``--vo=help``). @@ -273,37 +273,34 @@ Available video output drivers are: ``--vo-direct3d-exact-backbuffer`` Always resize the backbuffer to window size. -``opengl`` - OpenGL video output driver. It supports extended scaling methods, dithering - and color management. +``gpu`` + General purpose, customizable, GPU-accelerated video output driver. It + supports extended scaling methods, dithering, color management, custom + shaders, HDR, and more. - See `OpenGL renderer options`_ for options specific to this VO. + See `GPU renderer options`_ for options specific to this VO. By default, it tries to use fast and fail-safe settings. Use the - ``opengl-hq`` profile to use this driver with defaults set to high - quality rendering. (This profile is also the replacement for - ``--vo=opengl-hq``.) The profile can be applied with ``--profile=opengl-hq`` - and its contents can be viewed with ``--show-profile=opengl-hq``. + ``gpu-hq`` profile to use this driver with defaults set to high quality + rendering. The profile can be applied with ``--profile=gpu-hq`` and its + contents can be viewed with ``--show-profile=gpu-hq``. - Requires at least OpenGL 2.1. - - Some features are available with OpenGL 3 capable graphics drivers only - (or if the necessary extensions are available). - - OpenGL ES 2.0 and 3.0 are supported as well. + This VO abstracts over several possible graphics APIs and windowing + contexts, which can be influenced using the ``--gpu-api`` and + ``--gpu-context`` options. Hardware decoding over OpenGL-interop is supported to some degree. Note that in this mode, some corner case might not be gracefully handled, and color space conversion and chroma upsampling is generally in the hand of the hardware decoder APIs. - ``opengl`` makes use of FBOs by default. Sometimes you can achieve better - quality or performance by changing the ``--opengl-fbo-format`` option to + ``gpu`` makes use of FBOs by default. Sometimes you can achieve better + quality or performance by changing the ``--gpu-fbo-format`` option to ``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include Mesa/Intel not accepting ``rgb16``, Mesa sometimes not being compiled with float texture support, and some OS X setups being very slow with ``rgb16`` but fast with ``rgb32f``. If you have problems, you can also try enabling the - ``--opengl-dumb-mode=yes`` option. + ``--gpu-dumb-mode=yes`` option. ``sdl`` SDL 2.0+ Render video output driver, depending on system with or without diff --git a/DOCS/mplayer-changes.rst b/DOCS/mplayer-changes.rst index 7c8ec50a90..66cacb3205 100644 --- a/DOCS/mplayer-changes.rst +++ b/DOCS/mplayer-changes.rst @@ -76,8 +76,8 @@ Video * Wayland support. * Native support for VAAPI and VDA. Improved VDPAU video output. -* Improved OpenGL output (see the ``opengl-hq`` video output). -* Make hardware decoding work with the ``opengl`` video output. +* Improved GPU-accelerated video output (see the ``gpu-hq`` preset). +* Make hardware decoding work with the ``gpu`` video output. * Support for libavfilter (for video->video and audio->audio). This allows using most of FFmpeg's filters, which improve greatly on the old MPlayer filters in features, performance, and correctness. @@ -85,7 +85,7 @@ Video for BT.2020 (Ultra HD). linear XYZ (Digital Cinema) and SMPTE ST2084 (HDR) inputs. * Support for color managed displays, via ICC profiles. -* High-quality image resamplers (see the ``opengl`` ``scale`` suboption). +* High-quality image resamplers (see the ``--scale`` suboption). * Support for scaling in (sigmoidized) linear light. * Better subtitle rendering using libass by default. * Improvements when playing multiple files (``-fixed-vo`` is default, do not diff --git a/etc/builtin.conf b/etc/builtin.conf index 1d93df9606..ee46f8cb00 100644 --- a/etc/builtin.conf +++ b/etc/builtin.conf @@ -36,7 +36,7 @@ load-scripts=no osc=no framedrop=no -[opengl-hq] +[gpu-hq] scale=spline36 cscale=spline36 dscale=mitchell @@ -44,3 +44,7 @@ dither-depth=auto correct-downscaling=yes sigmoid-upscaling=yes deband=yes + +# Compatibility alias (deprecated) +[opengl-hq] +profile=gpu-hq diff --git a/etc/mpv.conf b/etc/mpv.conf index d72c9ee6d7..2a8f8b9f8b 100644 --- a/etc/mpv.conf +++ b/etc/mpv.conf @@ -52,9 +52,9 @@ # Keep the player window on top of all other windows. #ontop=yes -# Specify high quality video rendering preset (for OpenGL VO only) +# Specify high quality video rendering preset (for --vo=gpu only) # Can cause performance problems with some drivers and GPUs. -#profile=opengl-hq +#profile=gpu-hq # Force video to lock on the display's refresh rate, and change video and audio # speed to some degree to ensure synchronous playback - can cause problems diff --git a/options/options.c b/options/options.c index 7dc3b0b160..18b6bb8dd8 100644 --- a/options/options.c +++ b/options/options.c @@ -57,8 +57,8 @@ #include "video/out/drm_common.h" #endif -#if HAVE_GL -#include "video/out/opengl/hwdec.h" +#if HAVE_GPU +#include "video/out/gpu/hwdec.h" #endif static void print_version(struct mp_log *log) @@ -90,6 +90,7 @@ extern const struct m_obj_list af_obj_list; extern const struct m_obj_list vo_obj_list; extern const struct m_obj_list ao_obj_list; +extern const struct m_sub_options opengl_conf; extern const struct m_sub_options angle_conf; extern const struct m_sub_options cocoa_conf; @@ -687,10 +688,14 @@ const m_option_t mp_opts[] = { OPT_SUBSTRUCT("", vo, vo_sub_opts, 0), OPT_SUBSTRUCT("", demux_opts, demux_conf, 0), -#if HAVE_GL +#if HAVE_GPU OPT_SUBSTRUCT("", gl_video_opts, gl_video_conf, 0), #endif +#if HAVE_GL + OPT_SUBSTRUCT("", opengl_opts, opengl_conf, 0), +#endif + #if HAVE_EGL_ANGLE_WIN32 OPT_SUBSTRUCT("", angle_opts, angle_conf, 0), #endif diff --git a/options/options.h b/options/options.h index 895c12182b..c02b7a34ca 100644 --- a/options/options.h +++ b/options/options.h @@ -328,6 +328,7 @@ typedef struct MPOpts { struct gl_video_opts *gl_video_opts; struct angle_opts *angle_opts; + struct opengl_opts *opengl_opts; struct cocoa_opts *cocoa_opts; struct dvd_opts *dvd_opts; diff --git a/player/main.c b/player/main.c index 56a4f1d4cf..cf267fb170 100644 --- a/player/main.c +++ b/player/main.c @@ -297,21 +297,6 @@ static bool handle_help_options(struct MPContext *mpctx) return false; } -static void handle_deprecated_options(struct MPContext *mpctx) -{ - struct MPOpts *opts = mpctx->opts; - struct m_obj_settings *vo = opts->vo->video_driver_list; - if (vo && vo->name && strcmp(vo->name, "opengl-hq") == 0) { - MP_WARN(mpctx, - "--vo=opengl-hq is deprecated! Use --profile=opengl-hq instead.\n"); - // Fudge it. This will replace the --vo option too, which is why we - // unset/safe it, and later restore it. - talloc_free(vo->name); - vo->name = talloc_strdup(NULL, "opengl"); - m_config_set_profile(mpctx->mconfig, "opengl-hq", 0); - } -} - static int cfg_include(void *ctx, char *filename, int flags) { struct MPContext *mpctx = ctx; @@ -445,8 +430,6 @@ int mp_initialize(struct MPContext *mpctx, char **options) if (handle_help_options(mpctx)) return -2; - handle_deprecated_options(mpctx); - if (!print_libav_versions(mp_null_log, 0)) { // Using mismatched libraries can be legitimate, but even then it's // a bad idea. We don't acknowledge its usefulness and stability. diff --git a/video/out/gpu/context.c b/video/out/gpu/context.c new file mode 100644 index 0000000000..dbabba8b3b --- /dev/null +++ b/video/out/gpu/context.c @@ -0,0 +1,186 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common/common.h" +#include "common/msg.h" +#include "options/options.h" +#include "options/m_option.h" +#include "video/out/vo.h" + +#include "context.h" + +extern const struct ra_ctx_fns ra_ctx_glx; +extern const struct ra_ctx_fns ra_ctx_glx_probe; +extern const struct ra_ctx_fns ra_ctx_x11_egl; +extern const struct ra_ctx_fns ra_ctx_drm_egl; +extern const struct ra_ctx_fns ra_ctx_cocoa; +extern const struct ra_ctx_fns ra_ctx_wayland_egl; +extern const struct ra_ctx_fns ra_ctx_wgl; +extern const struct ra_ctx_fns ra_ctx_angle; +extern const struct ra_ctx_fns ra_ctx_dxinterop; +extern const struct ra_ctx_fns ra_ctx_rpi; +extern const struct ra_ctx_fns ra_ctx_mali; +extern const struct ra_ctx_fns ra_ctx_vdpauglx; + +static const struct ra_ctx_fns *contexts[] = { +// OpenGL contexts: +#if HAVE_RPI + &ra_ctx_rpi, +#endif +/* +#if HAVE_GL_COCOA + &ra_ctx_cocoa, +#endif +#if HAVE_EGL_ANGLE_WIN32 + &ra_ctx_angle, +#endif +#if HAVE_GL_WIN32 + &ra_ctx_wgl, +#endif +#if HAVE_GL_DXINTEROP + &ra_ctx_dxinterop, +#endif +*/ +#if HAVE_GL_X11 + &ra_ctx_glx_probe, +#endif +#if HAVE_EGL_X11 + &ra_ctx_x11_egl, +#endif +#if HAVE_GL_X11 + &ra_ctx_glx, +#endif +#if HAVE_GL_WAYLAND + &ra_ctx_wayland_egl, +#endif +#if HAVE_EGL_DRM + &ra_ctx_drm_egl, +#endif +#if HAVE_MALI_FBDEV + &ra_ctx_mali, +#endif +#if HAVE_VDPAU_GL_X11 + &ra_ctx_vdpauglx, +#endif +}; + +static bool get_help(struct mp_log *log, struct bstr param) +{ + if (bstr_equals0(param, "help")) { + mp_info(log, "GPU contexts / APIs:\n"); + mp_info(log, " auto (autodetect)\n"); + for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) + mp_info(log, " %s (%s)\n", contexts[n]->name, contexts[n]->type); + return true; + } + + return false; +} + +int ra_ctx_validate_api(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param) +{ + if (get_help(log, param)) + return M_OPT_EXIT; + if (bstr_equals0(param, "auto")) + return 1; + for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { + if (bstr_equals0(param, contexts[i]->type)) + return 1; + } + return M_OPT_INVALID; +} + +int ra_ctx_validate_context(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param) +{ + if (get_help(log, param)) + return M_OPT_EXIT; + if (bstr_equals0(param, "auto")) + return 1; + for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { + if (bstr_equals0(param, contexts[i]->name)) + return 1; + } + return M_OPT_INVALID; +} + +// Create a VO window and create a RA context on it. +// vo_flags: passed to the backend's create window function +struct ra_ctx *ra_ctx_create(struct vo *vo, const char *context_type, + const char *context_name, struct ra_ctx_opts opts) +{ + bool api_auto = !context_type || strcmp(context_type, "auto") == 0; + bool ctx_auto = !context_name || strcmp(context_name, "auto") == 0; + + if (ctx_auto) { + MP_VERBOSE(vo, "Probing for best GPU context.\n"); + opts.probing = true; + } + + // Hack to silence backend (X11/Wayland/etc.) errors. Kill it once backends + // are separate from `struct vo` + bool old_probing = vo->probing; + vo->probing = opts.probing; + + for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { + if (!opts.probing && strcmp(contexts[i]->name, context_name) != 0) + continue; + if (!api_auto && strcmp(contexts[i]->type, context_type) != 0) + continue; + + struct ra_ctx *ctx = talloc_ptrtype(NULL, ctx); + *ctx = (struct ra_ctx) { + .vo = vo, + .global = vo->global, + .log = mp_log_new(ctx, vo->log, contexts[i]->type), + .opts = opts, + .fns = contexts[i], + }; + + MP_VERBOSE(ctx, "Initializing GPU context '%s'\n", ctx->fns->name); + if (contexts[i]->init(ctx)) { + vo->probing = old_probing; + return ctx; + } + + talloc_free(ctx); + } + + // If we've reached this point, then none of the contexts matched the name + // requested, or the backend creation failed for all of them. + MP_ERR(vo, "Failed initializing any suitable GPU context!\n"); + vo->probing = old_probing; + return NULL; +} + +void ra_ctx_destroy(struct ra_ctx **ctx) +{ + if (*ctx) + (*ctx)->fns->uninit(*ctx); + talloc_free(*ctx); + *ctx = NULL; +} diff --git a/video/out/gpu/context.h b/video/out/gpu/context.h new file mode 100644 index 0000000000..42de59b75f --- /dev/null +++ b/video/out/gpu/context.h @@ -0,0 +1,95 @@ +#pragma once + +#include "video/out/vo.h" + +#include "config.h" +#include "ra.h" + +struct ra_ctx_opts { + int allow_sw; // allow software renderers + int want_alpha; // create an alpha framebuffer if possible + int debug; // enable debugging layers/callbacks etc. + bool probing; // the backend was auto-probed + int swapchain_depth; // max number of images to render ahead +}; + +struct ra_ctx { + struct vo *vo; + struct ra *ra; + struct mpv_global *global; + struct mp_log *log; + + struct ra_ctx_opts opts; + const struct ra_ctx_fns *fns; + struct ra_swapchain *swapchain; + + void *priv; +}; + +// The functions that make up a ra_ctx. +struct ra_ctx_fns { + const char *type; // API type (for --gpu-api) + const char *name; // name (for --gpu-context) + + // Resize the window, or create a new window if there isn't one yet. + // Currently, there is an unfortunate interaction with ctx->vo, and + // display size etc. are determined by it. + bool (*reconfig)(struct ra_ctx *ctx); + + // This behaves exactly like vo_driver.control(). + int (*control)(struct ra_ctx *ctx, int *events, int request, void *arg); + + // These behave exactly like vo_driver.wakeup/wait_events. They are + // optional. + void (*wakeup)(struct ra_ctx *ctx); + void (*wait_events)(struct ra_ctx *ctx, int64_t until_time_us); + + // Initialize/destroy the 'struct ra' and possibly the underlying VO backend. + // Not normally called by the user of the ra_ctx. + bool (*init)(struct ra_ctx *ctx); + void (*uninit)(struct ra_ctx *ctx); +}; + +// Extra struct for the swapchain-related functions so they can be easily +// inherited from helpers. +struct ra_swapchain { + struct ra_ctx *ctx; + struct priv *priv; + const struct ra_swapchain_fns *fns; + + bool flip_v; // flip the rendered image vertically (set by the swapchain) +}; + +struct ra_swapchain_fns { + // Gets the current framebuffer depth in bits (0 if unknown). Optional. + int (*color_depth)(struct ra_swapchain *sw); + + // Retrieves a screenshot of the framebuffer. These are always the right + // side up, regardless of ra_swapchain->flip_v. Optional. + struct mp_image *(*screenshot)(struct ra_swapchain *sw); + + // Called when rendering starts. Returns NULL on failure. This must be + // followed by submit_frame, to submit the rendered frame. + struct ra_tex *(*start_frame)(struct ra_swapchain *sw); + + // Present the frame. Issued in lockstep with start_frame, with rendering + // commands in between. The `frame` is just there for timing data, for + // swapchains smart enough to do something with it. + bool (*submit_frame)(struct ra_swapchain *sw, const struct vo_frame *frame); + + // Performs a buffer swap. This blocks for as long as necessary to meet + // params.swapchain_depth, or until the next vblank (for vsynced contexts) + void (*swap_buffers)(struct ra_swapchain *sw); +}; + +// Create and destroy a ra_ctx. This also takes care of creating and destroying +// the underlying `struct ra`, and perhaps the underlying VO backend. +struct ra_ctx *ra_ctx_create(struct vo *vo, const char *context_type, + const char *context_name, struct ra_ctx_opts opts); +void ra_ctx_destroy(struct ra_ctx **ctx); + +struct m_option; +int ra_ctx_validate_api(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param); +int ra_ctx_validate_context(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param); diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c new file mode 100644 index 0000000000..5fbc1aa4a9 --- /dev/null +++ b/video/out/gpu/hwdec.c @@ -0,0 +1,239 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include + +#include "config.h" + +#include "common/common.h" +#include "common/msg.h" +#include "options/m_config.h" +#include "hwdec.h" + +extern const struct ra_hwdec_driver ra_hwdec_vaegl; +extern const struct ra_hwdec_driver ra_hwdec_vaglx; +extern const struct ra_hwdec_driver ra_hwdec_videotoolbox; +extern const struct ra_hwdec_driver ra_hwdec_vdpau; +extern const struct ra_hwdec_driver ra_hwdec_dxva2egl; +extern const struct ra_hwdec_driver ra_hwdec_d3d11egl; +extern const struct ra_hwdec_driver ra_hwdec_d3d11eglrgb; +extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx; +extern const struct ra_hwdec_driver ra_hwdec_dxva2; +extern const struct ra_hwdec_driver ra_hwdec_cuda; +extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay; + +static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = { +#if HAVE_VAAPI_EGL + &ra_hwdec_vaegl, +#endif +#if HAVE_VAAPI_GLX + &ra_hwdec_vaglx, +#endif +#if HAVE_VDPAU_GL_X11 + &ra_hwdec_vdpau, +#endif +#if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL + &ra_hwdec_videotoolbox, +#endif +#if HAVE_D3D_HWACCEL + &ra_hwdec_d3d11egl, + &ra_hwdec_d3d11eglrgb, + #if HAVE_D3D9_HWACCEL + &ra_hwdec_dxva2egl, + #endif +#endif +#if HAVE_GL_DXINTEROP_D3D9 + &ra_hwdec_dxva2gldx, +#endif +#if HAVE_CUDA_HWACCEL + &ra_hwdec_cuda, +#endif +#if HAVE_RPI + &ra_hwdec_rpi_overlay, +#endif + NULL +}; + +static struct ra_hwdec *load_hwdec_driver(struct mp_log *log, struct ra *ra, + struct mpv_global *global, + struct mp_hwdec_devices *devs, + const struct ra_hwdec_driver *drv, + bool is_auto) +{ + struct ra_hwdec *hwdec = talloc(NULL, struct ra_hwdec); + *hwdec = (struct ra_hwdec) { + .driver = drv, + .log = mp_log_new(hwdec, log, drv->name), + .global = global, + .ra = ra, + .devs = devs, + .probing = is_auto, + .priv = talloc_zero_size(hwdec, drv->priv_size), + }; + mp_verbose(log, "Loading hwdec driver '%s'\n", drv->name); + if (hwdec->driver->init(hwdec) < 0) { + ra_hwdec_uninit(hwdec); + mp_verbose(log, "Loading failed.\n"); + return NULL; + } + return hwdec; +} + +struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra, + struct mpv_global *g, + struct mp_hwdec_devices *devs, + enum hwdec_type api) +{ + bool is_auto = HWDEC_IS_AUTO(api); + for (int n = 0; mpgl_hwdec_drivers[n]; n++) { + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + if ((is_auto || api == drv->api) && !drv->testing_only) { + struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, is_auto); + if (r) + return r; + } + } + return NULL; +} + +// Load by option name. +struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra, + struct mpv_global *g, + struct mp_hwdec_devices *devs, + const char *name) +{ + int g_hwdec_api; + mp_read_option_raw(g, "hwdec", &m_option_type_choice, &g_hwdec_api); + if (!name || !name[0]) + name = m_opt_choice_str(mp_hwdec_names, g_hwdec_api); + + int api_id = HWDEC_NONE; + for (int n = 0; mp_hwdec_names[n].name; n++) { + if (name && strcmp(mp_hwdec_names[n].name, name) == 0) + api_id = mp_hwdec_names[n].value; + } + + for (int n = 0; mpgl_hwdec_drivers[n]; n++) { + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + if (name && strcmp(drv->name, name) == 0) { + struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, false); + if (r) + return r; + } + } + + return ra_hwdec_load_api(log, ra, g, devs, api_id); +} + +int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param) +{ + bool help = bstr_equals0(param, "help"); + if (help) + mp_info(log, "Available hwdecs:\n"); + for (int n = 0; mpgl_hwdec_drivers[n]; n++) { + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + const char *api_name = m_opt_choice_str(mp_hwdec_names, drv->api); + if (help) { + mp_info(log, " %s [%s]\n", drv->name, api_name); + } else if (bstr_equals0(param, drv->name) || + bstr_equals0(param, api_name)) + { + return 1; + } + } + if (help) { + mp_info(log, " auto (loads best)\n" + " (other --hwdec values)\n" + "Setting an empty string means use --hwdec.\n"); + return M_OPT_EXIT; + } + if (!param.len) + return 1; // "" is treated specially + for (int n = 0; mp_hwdec_names[n].name; n++) { + if (bstr_equals0(param, mp_hwdec_names[n].name)) + return 1; + } + mp_fatal(log, "No hwdec backend named '%.*s' found!\n", BSTR_P(param)); + return M_OPT_INVALID; +} + +void ra_hwdec_uninit(struct ra_hwdec *hwdec) +{ + if (hwdec) + hwdec->driver->uninit(hwdec); + talloc_free(hwdec); +} + +bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt) +{ + for (int n = 0; hwdec->driver->imgfmts[n]; n++) { + if (hwdec->driver->imgfmts[n] == imgfmt) + return true; + } + return false; +} + +struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec, + struct mp_image_params *params) +{ + assert(ra_hwdec_test_format(hwdec, params->imgfmt)); + + struct ra_hwdec_mapper *mapper = talloc_ptrtype(NULL, mapper); + *mapper = (struct ra_hwdec_mapper){ + .owner = hwdec, + .driver = hwdec->driver->mapper, + .log = hwdec->log, + .ra = hwdec->ra, + .priv = talloc_zero_size(mapper, hwdec->driver->mapper->priv_size), + .src_params = *params, + .dst_params = *params, + }; + if (mapper->driver->init(mapper) < 0) + ra_hwdec_mapper_free(&mapper); + return mapper; +} + +void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper) +{ + struct ra_hwdec_mapper *p = *mapper; + if (p) { + ra_hwdec_mapper_unmap(p); + p->driver->uninit(p); + talloc_free(p); + } + *mapper = NULL; +} + +void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + if (mapper->driver->unmap) + mapper->driver->unmap(mapper); + mp_image_unrefp(&mapper->src); +} + +int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img) +{ + ra_hwdec_mapper_unmap(mapper); + mp_image_setrefp(&mapper->src, img); + if (mapper->driver->map(mapper) < 0) { + ra_hwdec_mapper_unmap(mapper); + return -1; + } + return 0; +} diff --git a/video/out/gpu/hwdec.h b/video/out/gpu/hwdec.h new file mode 100644 index 0000000000..20bbaae9eb --- /dev/null +++ b/video/out/gpu/hwdec.h @@ -0,0 +1,130 @@ +#ifndef MPGL_HWDEC_H_ +#define MPGL_HWDEC_H_ + +#include "video/mp_image.h" +#include "ra.h" +#include "video/hwdec.h" + +struct ra_hwdec { + const struct ra_hwdec_driver *driver; + struct mp_log *log; + struct mpv_global *global; + struct ra *ra; + struct mp_hwdec_devices *devs; + // GLSL extensions required to sample textures from this. + const char **glsl_extensions; + // For free use by hwdec driver + void *priv; + // For working around the vdpau vs. vaapi mess. + bool probing; + // Used in overlay mode only. + float overlay_colorkey[4]; +}; + +struct ra_hwdec_mapper { + const struct ra_hwdec_mapper_driver *driver; + struct mp_log *log; + struct ra *ra; + void *priv; + struct ra_hwdec *owner; + // Input frame parameters. (Set before init(), immutable.) + struct mp_image_params src_params; + // Output frame parameters (represents the format the textures return). Must + // be set by init(), immutable afterwards, + struct mp_image_params dst_params; + + // The currently mapped source image (or the image about to be mapped in + // ->map()). NULL if unmapped. The mapper can also clear this reference if + // the mapped textures contain a full copy. + struct mp_image *src; + + // The mapped textures and metadata about them. These fields change if a + // new frame is mapped (or unmapped), but otherwise remain constant. + // The common code won't mess with these, so you can e.g. set them in the + // .init() callback. + struct ra_tex *tex[4]; + bool vdpau_fields; +}; + +// This can be used to map frames of a specific hw format as GL textures. +struct ra_hwdec_mapper_driver { + // Used to create ra_hwdec_mapper.priv. + size_t priv_size; + + // Init the mapper implementation. At this point, the field src_params, + // fns, devs, priv are initialized. + int (*init)(struct ra_hwdec_mapper *mapper); + // Destroy the mapper. unmap is called before this. + void (*uninit)(struct ra_hwdec_mapper *mapper); + + // Map mapper->src as texture, and set mapper->frame to textures using it. + // It is expected that that the textures remain valid until the next unmap + // or uninit call. + // The function is allowed to unref mapper->src if it's not needed (i.e. + // this function creates a copy). + // The underlying format can change, so you might need to do some form + // of change detection. You also must reject unsupported formats with an + // error. + // On error, returns negative value on error and remains unmapped. + int (*map)(struct ra_hwdec_mapper *mapper); + // Unmap the frame. Does nothing if already unmapped. Optional. + void (*unmap)(struct ra_hwdec_mapper *mapper); +}; + +struct ra_hwdec_driver { + // Name of the interop backend. This is used for informational purposes only. + const char *name; + // Used to create ra_hwdec.priv. + size_t priv_size; + // Used to explicitly request a specific API. + enum hwdec_type api; + // One of the hardware surface IMGFMT_ that must be passed to map_image later. + // Terminated with a 0 entry. (Extend the array size as needed.) + const int imgfmts[3]; + // Dosn't load this unless requested by name. + bool testing_only; + + // Create the hwdec device. It must add it to hw->devs, if applicable. + int (*init)(struct ra_hwdec *hw); + void (*uninit)(struct ra_hwdec *hw); + + // This will be used to create a ra_hwdec_mapper from ra_hwdec. + const struct ra_hwdec_mapper_driver *mapper; + + // The following function provides an alternative API. Each ra_hwdec_driver + // must have either provide a mapper or overlay_frame (not both or none), and + // if overlay_frame is set, it operates in overlay mode. In this mode, + // OSD etc. is rendered via OpenGL, but the video is rendered as a separate + // layer below it. + // Non-overlay mode is strictly preferred, so try not to use overlay mode. + // Set the given frame as overlay, replacing the previous one. This can also + // just change the position of the overlay. + // hw_image==src==dst==NULL is passed to clear the overlay. + int (*overlay_frame)(struct ra_hwdec *hw, struct mp_image *hw_image, + struct mp_rect *src, struct mp_rect *dst, bool newframe); +}; + +struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra, + struct mpv_global *g, + struct mp_hwdec_devices *devs, + enum hwdec_type api); + +struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra, + struct mpv_global *g, + struct mp_hwdec_devices *devs, + const char *name); + +int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param); + +void ra_hwdec_uninit(struct ra_hwdec *hwdec); + +bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt); + +struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec, + struct mp_image_params *params); +void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper); +void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper); +int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img); + +#endif diff --git a/video/out/gpu/lcms.c b/video/out/gpu/lcms.c new file mode 100644 index 0000000000..8747ae6aa6 --- /dev/null +++ b/video/out/gpu/lcms.c @@ -0,0 +1,531 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include + +#include "mpv_talloc.h" + +#include "config.h" + +#include "stream/stream.h" +#include "common/common.h" +#include "misc/bstr.h" +#include "common/msg.h" +#include "options/m_option.h" +#include "options/path.h" +#include "video/csputils.h" +#include "lcms.h" + +#include "osdep/io.h" + +#if HAVE_LCMS2 + +#include +#include +#include + +struct gl_lcms { + void *icc_data; + size_t icc_size; + struct AVBufferRef *vid_profile; + char *current_profile; + bool using_memory_profile; + bool changed; + enum mp_csp_prim current_prim; + enum mp_csp_trc current_trc; + + struct mp_log *log; + struct mpv_global *global; + struct mp_icc_opts *opts; +}; + +static bool parse_3dlut_size(const char *arg, int *p1, int *p2, int *p3) +{ + if (sscanf(arg, "%dx%dx%d", p1, p2, p3) != 3) + return false; + for (int n = 0; n < 3; n++) { + int s = ((int[]) { *p1, *p2, *p3 })[n]; + if (s < 2 || s > 512) + return false; + } + return true; +} + +static int validate_3dlut_size_opt(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param) +{ + int p1, p2, p3; + char s[20]; + snprintf(s, sizeof(s), "%.*s", BSTR_P(param)); + return parse_3dlut_size(s, &p1, &p2, &p3); +} + +#define OPT_BASE_STRUCT struct mp_icc_opts +const struct m_sub_options mp_icc_conf = { + .opts = (const m_option_t[]) { + OPT_FLAG("use-embedded-icc-profile", use_embedded, 0), + OPT_STRING("icc-profile", profile, M_OPT_FILE), + OPT_FLAG("icc-profile-auto", profile_auto, 0), + OPT_STRING("icc-cache-dir", cache_dir, M_OPT_FILE), + OPT_INT("icc-intent", intent, 0), + OPT