[vlc-commits] [Git][videolan/vlc][master] 11 commits: opengl: copy tex sizes only once

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Sat Nov 20 19:47:51 UTC 2021



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
756d5b44 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: copy tex sizes only once

Move the initialization out of the loop.

- - - - -
99de535d by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: simplify framebuffers initialization

Only the tex_count assignment differs depending on the filter_planes
flag. The remaining code can be common to both branches.

- - - - -
f40db515 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: pass output size instead of aspect ratio

This prepares to expose output size changes to filters in a generic way.

- - - - -
17ca010c by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: add vlc_list_reverse_foreach()

It is sometimes useful to iterate backwards.

- - - - -
70fb9701 by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: add a comment for a test

- - - - -
2178f3af by Maxime Meissonnier at 2021-11-20T19:20:53+00:00
vlc_list: tests for reverse iteration

- - - - -
93c5565c by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: expose filter function to adapt size

Expose a function to recreate framebuffers and textures on output size
change.

Co-authored-by: Maxime Meissonnier <mmeisson at outlook.fr>

- - - - -
77db266e by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: handle output resize in a generic way

Resizing the window resulted in a call to a function on the specific
"renderer" filter.

Instead, add a filter callback to handle output resizing, and propagate
the requested input size backwards.

This will allow to properly handle resizing if an upscaler is inserted
before the renderer.

Co-authored-by: Maxime Meissonnier <mmeisson at outlook.fr>

- - - - -
c35ada81 by Romain Vimont at 2021-11-20T19:20:53+00:00
opengl: notify the next filter on size change

When a filter changes its output size as a result of
request_output_size(), notify the next filter via a callback.

- - - - -
e4e44fc2 by Romain Vimont at 2021-11-20T19:20:53+00:00
Add libplacebo scale OpenGL filter

Apply an upscaler or downscaler available through libplacebo.

- - - - -
5e14e1ed by Romain Vimont at 2021-11-20T19:20:53+00:00
Enable pl_scale filter in OpenGL vout if requested

If --pl-upscaler or --pl-downscaler (the same options as in the
libplacebo vout) are passed, run the pl_scale filter in the OpenGL vout.

- - - - -


20 changed files:

- configure.ac
- include/vlc_list.h
- modules/video_output/caopengllayer.m
- modules/video_output/libplacebo/utils.c
- modules/video_output/libplacebo/utils.h
- modules/video_output/macosx.m
- modules/video_output/opengl/Makefile.am
- modules/video_output/opengl/display.c
- modules/video_output/opengl/filter.c
- modules/video_output/opengl/filter.h
- modules/video_output/opengl/filter_priv.h
- modules/video_output/opengl/filters.c
- modules/video_output/opengl/filters.h
- + modules/video_output/opengl/pl_scale.c
- modules/video_output/opengl/renderer.c
- modules/video_output/opengl/renderer.h
- modules/video_output/opengl/vout_helper.c
- modules/video_output/opengl/vout_helper.h
- modules/video_output/win32/glwin32.c
- src/test/list.c


Changes:

=====================================
configure.ac
=====================================
@@ -3179,6 +3179,11 @@ AS_IF([test "$enable_libplacebo" != "no"], [
 ])
 AM_CONDITIONAL([HAVE_LIBPLACEBO], [test "$enable_libplacebo" != "no"])
 
+dnl
+dnl  OpenGL filter pl_scale
+dnl
+PKG_HAVE_WITH_MODULES([LIBPLACEBO_SCALE], [libplacebo >= 4.167])
+
 dnl
 dnl  OpenGL
 dnl


=====================================
include/vlc_list.h
=====================================
@@ -217,6 +217,14 @@ struct vlc_list_it vlc_list_it_start(const struct vlc_list *head)
     return it;
 }
 
+static inline
+struct vlc_list_it vlc_list_it_reverse_start(const struct vlc_list *head)
+{
+    struct vlc_list *first = head->prev;
+
+    return (struct vlc_list_it){ head, first, first->prev };
+}
+
 static inline bool vlc_list_it_continue(const struct vlc_list_it *restrict it)
 {
     return it->current != it->head;
@@ -230,6 +238,14 @@ static inline void vlc_list_it_next(struct vlc_list_it *restrict it)
     it->next = next->next;
 }
 
+static inline void vlc_list_it_prev(struct vlc_list_it *restrict it)
+{
+    struct vlc_list *next = it->next;
+
+    it->current = next;
+    it->next = next->prev;
+}
+
 #define vlc_list_entry_aligned_size(p) \
     ((sizeof (*(p)) + sizeof (max_align_t) - 1) / sizeof (max_align_t))
 
@@ -266,6 +282,28 @@ static inline void vlc_list_it_next(struct vlc_list_it *restrict it)
                                        pos, member), true); \
          vlc_list_it_next(&(vlc_list_it__##pos)))
 
+/**
+ * List iteration macro.
+ *
+ * This macro iterates over all elements (excluding the head) of a list,
+ * in reversed order from the first to the last.
+ *
+ * For each iteration, it sets the cursor variable to the current element.
+ *
+ * \param pos Cursor pointer variable identifier.
+ * \param head Head pointer of the list to iterate [IN].
+ * \param member Identifier of the member of the data type
+ *               serving as list node.
+ * \note It it safe to delete the current item while iterating.
+ * It is however <b>not</b> safe to delete another item.
+ */
+#define vlc_list_reverse_foreach(pos, head, member) \
+    for (struct vlc_list_it vlc_list_it_##pos = vlc_list_it_reverse_start(head); \
+         vlc_list_it_continue(&(vlc_list_it_##pos)) \
+          && ((pos) = vlc_list_entry_p((vlc_list_it_##pos).current, \
+                                       pos, member), true); \
+         vlc_list_it_prev(&(vlc_list_it_##pos)))
+
 /**
  * Converts a list node pointer to an element pointer.
  *


=====================================
modules/video_output/caopengllayer.m
=====================================
@@ -343,7 +343,7 @@ static int Control (vout_display_t *vd, int query)
                 // don't return an error or we need to handle reset_pictures
                 return VLC_SUCCESS;
 
-            vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)place.width / place.height);
+            vout_display_opengl_SetOutputSize(sys->vgl, place.width, place.height);
             OpenglUnlock(sys->gl);
 
             sys->place = place;


=====================================
modules/video_output/libplacebo/utils.c
=====================================
@@ -465,3 +465,20 @@ enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *fmt)
 
     return locs[fmt->chroma_location];
 }
+
+int vlc_placebo_PlaneComponents(const video_format_t *fmt,
+                                struct pl_plane planes[4]) {
+    const struct fmt_desc *desc = FindDesc(fmt->i_chroma);
+    if (!desc)
+        return 0;
+
+    for (int i = 0; i < desc->num_planes; i++) {
+        const struct plane_desc *p = &desc->planes[i];
+
+        planes[i].components = p->components;
+        for (int c = 0; c < p->components; ++c)
+            planes[i].component_mapping[c] = p->comp_map[c];
+    }
+
+    return desc->num_planes;
+}


=====================================
modules/video_output/libplacebo/utils.h
=====================================
@@ -36,6 +36,8 @@ struct pl_color_space vlc_placebo_ColorSpace(const video_format_t *);
 struct pl_color_repr vlc_placebo_ColorRepr(const video_format_t *);
 enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *);
 
+int vlc_placebo_PlaneComponents(const video_format_t *, struct pl_plane[4]);
+
 // Fill a pl_plane_data array with various data. Returns the number of planes,
 // or 0 if the format is unsupported by the libplacebo API. If `buf` is set,
 // then all addresses of the picture_t must lie within `buf`'s mapped memory.


=====================================
modules/video_output/macosx.m
=====================================
@@ -373,7 +373,7 @@ static int Control (vout_display_t *vd, int query)
 
                 if (vlc_gl_MakeCurrent (sys->gl) != VLC_SUCCESS)
                     return VLC_SUCCESS;
-                vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)place.width / place.height);
+                vout_display_opengl_SetOutputSize(sys->vgl, place.width, place.height);
 
                 /* For resize, we call glViewport in reshape and not here.
                  This has the positive side effect that we avoid erratic sizing as we animate every resize. */


=====================================
modules/video_output/opengl/Makefile.am
=====================================
@@ -124,6 +124,34 @@ libglfilter_mock_plugin_la_CFLAGS = -DUSE_OPENGL_ES2=1
 noinst_LTLIBRARIES += libglfilter_mock_plugin.la
 endif
 
+if HAVE_LIBPLACEBO_SCALE
+
+libpl_scale_plugin_la_SOURCES = video_output/opengl/pl_scale.c
+libpl_scale_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBPLACEBO_CFLAGS)
+libpl_scale_plugin_la_LIBADD = $(LIBPLACEBO_LIBS)
+if HAVE_GL
+libpl_scale_plugin_la_LIBADD += libvlc_opengl.la
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+endif
+
+if HAVE_DARWIN
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+if HAVE_OSX
+libpl_scale_plugin_la_LIBADD += libvlc_opengl.la
+else
+libpl_scale_plugin_la_LIBADD += libvlc_opengles.la
+libpl_scale_plugin_la_CPPFLAGS += -DUSE_OPENGL_ES2=1
+endif
+endif
+
+if HAVE_ANDROID
+libpl_scale_plugin_la_LIBADD += libvlc_opengles.la
+libpl_scale_plugin_la_CPPFLAGS += -DUSE_OPENGL_ES2=1
+video_filter_LTLIBRARIES += libpl_scale_plugin.la
+endif
+
+endif
+
 libegl_display_generic_plugin_la_SOURCES = video_output/opengl/egl_display_generic.c
 libegl_display_generic_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(EGL_FLAGS)
 libegl_display_generic_plugin_la_LIBADD = $(EGL_LIBS)


=====================================
modules/video_output/opengl/display.c
=====================================
@@ -225,8 +225,8 @@ static void PictureDisplay (vout_display_t *vd, picture_t *pic)
     {
         if (sys->place_changed)
         {
-            float window_ar = (float)sys->place.width / sys->place.height;
-            vout_display_opengl_SetWindowAspectRatio(sys->vgl, window_ar);
+            vout_display_opengl_SetOutputSize(sys->vgl, sys->place.width,
+                                                        sys->place.height);
             vout_display_opengl_Viewport(sys->vgl, sys->place.x, sys->place.y,
                                          sys->place.width, sys->place.height);
             sys->place_changed = false;


=====================================
modules/video_output/opengl/filter.c
=====================================
@@ -184,42 +184,23 @@ InitFramebuffersOut(struct vlc_gl_filter_priv *priv)
 
     struct vlc_gl_filter *filter = &priv->filter;
     if (filter->config.filter_planes)
-    {
-        struct vlc_gl_format *glfmt = &priv->glfmt_in;
-
-        priv->tex_count = glfmt->tex_count;
-        vt->GenFramebuffers(priv->tex_count, priv->framebuffers_out);
-        vt->GenTextures(priv->tex_count, priv->textures_out);
-
-        for (unsigned i = 0; i < glfmt->tex_count; ++i)
-        {
-            memcpy(priv->tex_widths, priv->plane_widths,
-                   priv->tex_count * sizeof(*priv->tex_widths));
-            memcpy(priv->tex_heights, priv->plane_heights,
-                   priv->tex_count * sizeof(*priv->tex_heights));
-            /* Init one framebuffer and texture for each plane */
-            int ret =
-                InitPlane(priv, i, priv->tex_widths[i], priv->tex_heights[i]);
-            if (ret != VLC_SUCCESS)
-            {
-                DeleteFramebuffersOut(priv);
-                return ret;
-            }
-        }
-    }
+        priv->tex_count = priv->glfmt_in.tex_count;
     else
-    {
         priv->tex_count = 1;
 
-        /* Create a texture having the expected size */
-
-        vt->GenFramebuffers(1, priv->framebuffers_out);
-        vt->GenTextures(1, priv->textures_out);
+    vt->GenFramebuffers(priv->tex_count, priv->framebuffers_out);
+    vt->GenTextures(priv->tex_count, priv->textures_out);
 
-        priv->tex_widths[0] = priv->size_out.width;
-        priv->tex_heights[0] = priv->size_out.height;
+    memcpy(priv->tex_widths, priv->plane_widths,
+           priv->tex_count * sizeof(*priv->tex_widths));
+    memcpy(priv->tex_heights, priv->plane_heights,
+           priv->tex_count * sizeof(*priv->tex_heights));
 
-        int ret = InitPlane(priv, 0, priv->tex_widths[0], priv->tex_heights[0]);
+    for (unsigned i = 0; i < priv->tex_count; ++i)
+    {
+        /* Init one framebuffer and texture for each plane */
+        int ret =
+            InitPlane(priv, i, priv->tex_widths[i], priv->tex_heights[i]);
         if (ret != VLC_SUCCESS)
         {
             DeleteFramebuffersOut(priv);
@@ -314,3 +295,42 @@ vlc_gl_filter_InitPlaneSizes(struct vlc_gl_filter *filter)
         priv->plane_heights[0] = priv->size_out.height;
     }
 }
+
+void
+vlc_gl_filter_ApplyOutputSize(struct vlc_gl_filter *filter)
+{
+    struct vlc_gl_filter_priv *priv = vlc_gl_filter_PRIV(filter);
+
+    vlc_gl_filter_InitPlaneSizes(filter);
+
+    const opengl_vtable_t *vt = &priv->filter.api->vt;
+    GL_ASSERT_NOERROR(vt);
+
+    unsigned msaa_level = filter->config.msaa_level;
+    if (msaa_level)
+    {
+        vt->BindRenderbuffer(GL_RENDERBUFFER, priv->renderbuffer_msaa);
+        vt->RenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level,
+                                           GL_RGBA8,
+                                           priv->size_out.width,
+                                           priv->size_out.height);
+    }
+
+    if (priv->tex_count)
+    {
+        memcpy(priv->tex_widths, priv->plane_widths,
+               priv->tex_count * sizeof(*priv->tex_widths));
+        memcpy(priv->tex_heights, priv->plane_heights,
+               priv->tex_count * sizeof(*priv->tex_heights));
+
+        for (unsigned plane = 0; plane < priv->tex_count; ++plane)
+        {
+            vt->BindTexture(GL_TEXTURE_2D, priv->textures_out[plane]);
+            vt->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, priv->tex_widths[plane],
+                           priv->tex_heights[plane], 0, GL_RGBA,
+                           GL_UNSIGNED_BYTE, NULL);
+        }
+    }
+
+    GL_ASSERT_NOERROR(vt);
+}


=====================================
modules/video_output/opengl/filter.h
=====================================
@@ -62,6 +62,37 @@ struct vlc_gl_filter_ops {
      * Free filter resources
      */
     void (*close)(struct vlc_gl_filter *filter);
+
+    /**
+     * Request a (responsive) filter to adapt its output size (optional)
+     *
+     * A responsive filter is a filter for which the size of the produced
+     * pictures depends on the output (e.g. display) size rather than the
+     * input. This is for example the case for a renderer.
+     *
+     * A new output size is requested (size_out). The filter is authorized to
+     * change the size_out to enforce its own constraints.
+     *
+     * In addition, it may request to the previous filter (if any) an optimal
+     * size it wants to receive. If set to non-zero value, this previous filter
+     * will receive this size as its requested size (and so on).
+     *
+     * \retval true if the resize is accepted (possibly with a modified
+     *              size_out)
+     * \retval false if the resize is rejected (included on error)
+     */
+    int (*request_output_size)(struct vlc_gl_filter *filter,
+                               struct vlc_gl_tex_size *size_out,
+                               struct vlc_gl_tex_size *optimal_in);
+
+    /**
+     * Callback to notify input size changes
+     *
+     * When a filter changes its output size as a result of
+     * request_output_size(), the next filter is notified by this callback.
+     */
+    void (*on_input_size_change)(struct vlc_gl_filter *filter,
+                                 const struct vlc_gl_tex_size *size);
 };
 
 /**


=====================================
modules/video_output/opengl/filter_priv.h
=====================================
@@ -94,4 +94,7 @@ vlc_gl_filter_InitFramebuffers(struct vlc_gl_filter *filter, bool is_last);
 void
 vlc_gl_filter_InitPlaneSizes(struct vlc_gl_filter *filter);
 
+void
+vlc_gl_filter_ApplyOutputSize(struct vlc_gl_filter *filter);
+
 #endif


=====================================
modules/video_output/opengl/filters.c
=====================================
@@ -517,3 +517,55 @@ vlc_gl_filters_SetViewport(struct vlc_gl_filters *filters, int x, int y,
     filters->viewport.width = width;
     filters->viewport.height = height;
 }
+
+int
+vlc_gl_filters_SetOutputSize(struct vlc_gl_filters *filters, unsigned width,
+                             unsigned height)
+{
+    bool resized = false;
+    struct vlc_gl_tex_size req = { width, height };
+
+    struct vlc_gl_filter *next = NULL;
+
+    struct vlc_gl_filter_priv *priv;
+    vlc_list_reverse_foreach(priv, &filters->list, node)
+    {
+        struct vlc_gl_filter *filter = &priv->filter;
+        if (!filter->ops->request_output_size) {
+            /* Could not propagate further */
+            break;
+        }
+
+        struct vlc_gl_tex_size optimal_in = {0};
+        int ret =
+            filter->ops->request_output_size(filter, &req, &optimal_in);
+        if (ret != VLC_SUCCESS)
+            break;
+
+        /* The filter may have modified the requested size */
+        priv->size_out = req;
+
+        /* Recreate the framebuffers/textures with the new size */
+        vlc_gl_filter_ApplyOutputSize(filter);
+
+        resized = true;
+
+        /* Notify the next filter of the input size change */
+        if (next && next->ops->on_input_size_change)
+            next->ops->on_input_size_change(next, &req);
+
+        if (!optimal_in.width || !optimal_in.height)
+            /* No specific input size requested, do not propagate further */
+            break;
+
+        /* Request the previous filter to output at the optimal input size of
+         * the current filter. */
+        req = optimal_in;
+
+        /* The filters are iterated backwards, so the current filter will
+         * become the next filter. */
+        next = filter;
+    }
+
+    return resized ? VLC_SUCCESS : VLC_EGENERIC;
+}


=====================================
modules/video_output/opengl/filters.h
=====================================
@@ -106,4 +106,11 @@ void
 vlc_gl_filters_SetViewport(struct vlc_gl_filters *filters, int x, int y,
                            unsigned width, unsigned height);
 
+/**
+ * Change the output size
+ */
+int
+vlc_gl_filters_SetOutputSize(struct vlc_gl_filters *filters, unsigned width,
+                             unsigned height);
+
 #endif


=====================================
modules/video_output/opengl/pl_scale.c
=====================================
@@ -0,0 +1,367 @@
+/*****************************************************************************
+ * pl_scale.c
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "limits.h"
+
+#include <vlc_common.h>
+#include <vlc_picture.h>
+#include <vlc_plugin.h>
+#include <vlc_modules.h>
+#include <vlc_opengl.h>
+#include <vlc_filter.h>
+
+#include <libplacebo/context.h>
+#include <libplacebo/gpu.h>
+#include <libplacebo/opengl.h>
+#include <libplacebo/renderer.h>
+
+#include "video_output/opengl/filter.h"
+#include "video_output/opengl/gl_api.h"
+#include "video_output/opengl/gl_common.h"
+#include "video_output/opengl/gl_util.h"
+#include "video_output/opengl/sampler.h"
+#include "video_output/libplacebo/utils.h"
+
+// Without this commit, libplacebo as used by this filter makes VLC
+// assert/crash by closing file descriptors:
+// https://github.com/haasn/libplacebo/commit/39fc39d31d65968709b4a05c571a0d85c918058d
+static_assert(PL_API_VER >= 167, "pl_scale requires libplacebo >= 4.167");
+
+#define CFG_PREFIX "plscale-"
+
+static const char *const filter_options[] = {
+    "upscaler", "downscaler", NULL,
+};
+
+struct sys
+{
+    GLuint id;
+    GLuint vbo;
+
+    pl_log pl_log;
+    pl_opengl pl_opengl;
+    pl_renderer pl_renderer;
+
+    /* Cached representation of pl_frame to wrap the raw textures */
+    struct pl_frame frame_in;
+    struct pl_frame frame_out;
+    struct pl_render_params render_params;
+
+    unsigned out_width;
+    unsigned out_height;
+};
+
+static void
+DestroyTextures(pl_gpu gpu, unsigned count, pl_tex textures[])
+{
+    for (unsigned i = 0; i < count; ++i)
+        pl_tex_destroy(gpu, &textures[i]);
+}
+
+static int
+WrapTextures(pl_gpu gpu, unsigned count, const GLuint textures[],
+             const GLsizei tex_widths[], const GLsizei tex_heights[],
+             GLenum tex_target, pl_tex out[])
+{
+    for (unsigned i = 0; i < count; ++i)
+    {
+        struct pl_opengl_wrap_params opengl_wrap_params = {
+            .texture = textures[i],
+            .width = tex_widths[i],
+            .height = tex_heights[i],
+            .target = tex_target,
+            .iformat = GL_RGBA8,
+        };
+
+        out[i] = pl_opengl_wrap(gpu, &opengl_wrap_params);
+        if (!out[i])
+        {
+            if (i)
+                DestroyTextures(gpu, i - 1, out);
+            return VLC_EGENERIC;
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
+static pl_tex
+WrapFramebuffer(pl_gpu gpu, GLuint framebuffer, unsigned width, unsigned height)
+{
+    struct pl_opengl_wrap_params opengl_wrap_params = {
+        .framebuffer = framebuffer,
+        .width = width,
+        .height = height,
+        .iformat = GL_RGBA8,
+    };
+
+    return pl_opengl_wrap(gpu, &opengl_wrap_params);
+}
+
+static int
+Draw(struct vlc_gl_filter *filter, const struct vlc_gl_picture *pic,
+     const struct vlc_gl_input_meta *meta)
+{
+    (void) meta;
+
+    struct sys *sys = filter->sys;
+    const opengl_vtable_t *vt = &filter->api->vt;
+    const struct vlc_gl_format *glfmt = filter->glfmt_in;
+    pl_gpu gpu = sys->pl_opengl->gpu;
+    struct pl_frame *frame_in = &sys->frame_in;
+    struct pl_frame *frame_out = &sys->frame_out;
+    struct pl_render_params *render_params = &sys->render_params;
+
+    if (pic->mtx_has_changed)
+    {
+        const float *mtx = pic->mtx;
+
+        /* The direction is either horizontal or vertical, and the two vectors
+         * are orthogonal */
+        assert((!mtx[1] && !mtx[2]) || (!mtx[0] && !mtx[3]));
+
+        /* Is the video rotated by 90° (or 270°)? */
+        bool rotated90 = !mtx[0];
+
+        /*
+         * The same rotation+flip orientation may be encoded in different ways
+         * in libplacebo. For example, hflip the crop rectangle and use a 90°
+         * rotation is equivalent to vflip the crop rectangle and use a 270°
+         * rotation.
+         *
+         * To get a unique solution, limit the rotation to be either 0 or 90,
+         * and encode the remaining in the crop rectangle.
+         */
+        frame_in->rotation = rotated90 ? PL_ROTATION_90 : PL_ROTATION_0;
+
+        /* Apply 90° to the coords if necessary */
+        float coords[] = {
+            rotated90 ? 1 : 0, 0,
+            rotated90 ? 0 : 1, 1,
+        };
+
+        vlc_gl_picture_ToTexCoords(pic, 2, coords, coords);
+
+        unsigned w = glfmt->tex_widths[0];
+        unsigned h = glfmt->tex_heights[0];
+        struct pl_rect2df *r = &frame_in->crop;
+        r->x0 = coords[0] * w;
+        r->y0 = coords[1] * h;
+        r->x1 = coords[2] * w;
+        r->y1 = coords[3] * h;
+    }
+
+    GLint value;
+    vt->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value);
+    GLuint final_draw_framebuffer = value; /* as GLuint */
+
+    pl_tex texs_in[PICTURE_PLANE_MAX];
+    int ret = WrapTextures(gpu, glfmt->tex_count, pic->textures,
+                           glfmt->tex_widths, glfmt->tex_heights,
+                           glfmt->tex_target, texs_in);
+    if (ret != VLC_SUCCESS)
+        goto end;
+
+    /* Only changes the plane textures from the cached pl_frame */
+    for (unsigned i = 0; i < glfmt->tex_count; ++i)
+        frame_in->planes[i].texture = texs_in[i];
+
+    pl_tex tex_out = WrapFramebuffer(gpu, final_draw_framebuffer,
+                                     sys->out_width, sys->out_height);
+    if (!tex_out)
+        goto destroy_texs_in;
+
+    frame_out->planes[0].texture = tex_out;
+
+    bool ok = pl_render_image(sys->pl_renderer, frame_in, frame_out,
+                              render_params);
+    if (!ok)
+        ret = VLC_EGENERIC;
+
+    DestroyTextures(gpu, 1, &tex_out);
+destroy_texs_in:
+    DestroyTextures(gpu, glfmt->tex_count, texs_in);
+
+end:
+    vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, final_draw_framebuffer);
+
+    return ret;
+}
+
+static int
+RequestOutputSize(struct vlc_gl_filter *filter,
+                  struct vlc_gl_tex_size *req,
+                  struct vlc_gl_tex_size *optimal_in)
+{
+    struct sys *sys = filter->sys;
+
+    sys->out_width = req->width;
+    sys->out_height = req->height;
+
+    /* Do not propagate resizing to previous filters */
+    (void) optimal_in;
+
+    return VLC_SUCCESS;
+}
+
+static void
+Close(struct vlc_gl_filter *filter)
+{
+    struct sys *sys = filter->sys;
+
+    pl_renderer_destroy(&sys->pl_renderer);
+    pl_opengl_destroy(&sys->pl_opengl);
+    pl_log_destroy(&sys->pl_log);
+
+    free(sys);
+}
+
+static vlc_gl_filter_open_fn Open;
+static int
+Open(struct vlc_gl_filter *filter, const config_chain_t *config,
+     const struct vlc_gl_format *glfmt, struct vlc_gl_tex_size *size_out)
+{
+    (void) config;
+
+    /* By default, do not scale. The dimensions will be modified dynamically by
+     * request_output_size(). */
+    unsigned width = glfmt->tex_widths[0];
+    unsigned height = glfmt->tex_heights[0];
+
+    config_ChainParse(filter, CFG_PREFIX, filter_options, config);
+    int upscaler = var_InheritInteger(filter, CFG_PREFIX "upscaler");
+    int downscaler = var_InheritInteger(filter, CFG_PREFIX "downscaler");
+
+    if (upscaler < 0 || (size_t) upscaler >= ARRAY_SIZE(scale_values)
+            || upscaler == SCALE_CUSTOM)
+    {
+        msg_Err(filter, "Unsupported upscaler: %d", upscaler);
+        return VLC_EGENERIC;
+    }
+
+    if (downscaler < 0 || (size_t) downscaler >= ARRAY_SIZE(scale_values)
+            || downscaler == SCALE_CUSTOM)
+    {
+        msg_Err(filter, "Unsupported downscaler: %d", downscaler);
+        return VLC_EGENERIC;
+    }
+
+    struct sys *sys = filter->sys = malloc(sizeof(*sys));
+    if (!sys)
+        return VLC_EGENERIC;
+
+    sys->pl_log = vlc_placebo_CreateContext(VLC_OBJECT(filter));
+    if (!sys->pl_log)
+        goto error_free_sys;
+
+    struct pl_opengl_params opengl_params = {
+        .debug = true,
+    };
+    sys->pl_opengl = pl_opengl_create(sys->pl_log, &opengl_params);
+
+    if (!sys->pl_opengl)
+        goto error_destroy_pl_log;
+
+    pl_gpu gpu = sys->pl_opengl->gpu;
+    sys->pl_renderer = pl_renderer_create(sys->pl_log, gpu);
+    if (!sys->pl_renderer)
+        goto error_destroy_pl_opengl;
+
+    sys->frame_in = (struct pl_frame) {
+        .num_planes = glfmt->tex_count,
+        .repr = vlc_placebo_ColorRepr(&glfmt->fmt),
+        .color = vlc_placebo_ColorSpace(&glfmt->fmt),
+    };
+
+    /* Initialize frame_in.planes */
+    int plane_count =
+        vlc_placebo_PlaneComponents(&glfmt->fmt, sys->frame_in.planes);
+    if ((unsigned) plane_count != glfmt->tex_count) {
+        msg_Err(filter, "Unexpected plane count (%d) != tex count (%u)",
+                        plane_count, glfmt->tex_count);
+        goto error_destroy_pl_opengl;
+    }
+
+    sys->frame_out = (struct pl_frame) {
+        .num_planes = 1,
+        .planes = {
+            {
+                .components = 4,
+                .component_mapping = {
+                    PL_CHANNEL_R,
+                    PL_CHANNEL_G,
+                    PL_CHANNEL_B,
+                    PL_CHANNEL_A,
+                },
+            },
+        },
+    };
+
+    sys->render_params = pl_render_default_params;
+    sys->render_params.upscaler = scale_config[upscaler];
+    sys->render_params.downscaler = scale_config[downscaler];
+
+    static const struct vlc_gl_filter_ops ops = {
+        .draw = Draw,
+        .close = Close,
+        .request_output_size = RequestOutputSize,
+    };
+    filter->ops = &ops;
+
+    sys->out_width = size_out->width = width;
+    sys->out_height = size_out->height = height;
+
+    return VLC_SUCCESS;
+
+error_destroy_pl_opengl:
+    pl_opengl_destroy(&sys->pl_opengl);
+error_destroy_pl_log:
+    pl_log_destroy(&sys->pl_log);
+error_free_sys:
+    free(sys);
+
+    return VLC_EGENERIC;
+}
+
+vlc_module_begin()
+    set_shortname("pl_scale")
+    set_description("OpenGL scaler")
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VFILTER)
+    set_capability("opengl filter", 0)
+    set_callback(Open)
+    add_shortcut("pl_scale");
+
+#define UPSCALER_TEXT "OpenGL upscaler"
+#define UPSCALER_LONGTEXT "Upscaler filter to apply during rendering"
+    add_integer(CFG_PREFIX "upscaler", SCALE_BUILTIN, UPSCALER_TEXT, \
+                UPSCALER_LONGTEXT) \
+        change_integer_list(scale_values, scale_text) \
+
+#define DOWNSCALER_TEXT "OpenGL downscaler"
+#define DOWNSCALER_LONGTEXT "Downscaler filter to apply during rendering"
+    add_integer(CFG_PREFIX "downscaler", SCALE_BUILTIN, DOWNSCALER_TEXT, \
+                DOWNSCALER_LONGTEXT) \
+        change_integer_list(scale_values, scale_text) \
+vlc_module_end()


=====================================
modules/video_output/opengl/renderer.c
=====================================
@@ -359,13 +359,17 @@ vlc_gl_renderer_SetViewpoint(struct vlc_gl_renderer *renderer,
     return VLC_SUCCESS;
 }
 
-void
-vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
-                                     float f_sar)
+static void
+vlc_gl_renderer_SetOutputSize(struct vlc_gl_renderer *renderer, unsigned width,
+                              unsigned height)
 {
+    float f_sar = (float) width / height;
+
     /* Each time the window size changes, we must recompute the minimum zoom
      * since the aspect ration changes.
      * We must also set the new current zoom value. */
+    renderer->target_width = width;
+    renderer->target_height = height;
     renderer->f_sar = f_sar;
     UpdateFOVy(renderer);
     UpdateZ(renderer);
@@ -374,6 +378,23 @@ vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
     getViewpointMatrixes(renderer, fmt->projection_mode);
 }
 
+static int
+RequestOutputSize(struct vlc_gl_filter *filter,
+                  struct vlc_gl_tex_size *req,
+                  struct vlc_gl_tex_size *optimal_in)
+{
+    struct vlc_gl_renderer *renderer = filter->sys;
+
+    vlc_gl_renderer_SetOutputSize(renderer, req->width, req->height);
+
+    /* The optimal input size is the size for which the renderer do not need to
+     * scale */
+    optimal_in->width = renderer->target_width;
+    optimal_in->height = renderer->target_height;
+
+    return VLC_SUCCESS;
+}
+
 static int BuildSphere(GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *nbVertices,
                        GLushort **indices, unsigned *nbIndices)
 {
@@ -760,6 +781,7 @@ vlc_gl_renderer_Open(struct vlc_gl_filter *filter,
     static const struct vlc_gl_filter_ops filter_ops = {
         .draw = Draw,
         .close = Close,
+        .request_output_size = RequestOutputSize,
     };
     filter->ops = &filter_ops;
     filter->sys = renderer;


=====================================
modules/video_output/opengl/renderer.h
=====================================
@@ -94,6 +94,11 @@ struct vlc_gl_renderer
     float f_fovy; /* to avoid recalculating them when needed.      */
     float f_z;    /* Position of the camera on the shpere radius vector */
     float f_sar;
+
+    /* Original size from which f_sar is computed
+     *     f_sar = (float) target_width / target_height */
+    unsigned target_width;
+    unsigned target_height;
 };
 
 vlc_gl_filter_open_fn vlc_gl_renderer_Open;
@@ -102,8 +107,4 @@ int
 vlc_gl_renderer_SetViewpoint(struct vlc_gl_renderer *renderer,
                              const vlc_viewpoint_t *p_vp);
 
-void
-vlc_gl_renderer_SetWindowAspectRatio(struct vlc_gl_renderer *renderer,
-                                     float f_sar);
-
 #endif /* include-guard */


=====================================
modules/video_output/opengl/vout_helper.c
=====================================
@@ -147,6 +147,34 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
         goto delete_interop;
     }
 
+    int upscaler = var_InheritInteger(gl, "pl-upscaler");
+    int downscaler = var_InheritInteger(gl, "pl-downscaler");
+
+    if (upscaler || downscaler)
+    {
+        char upscaler_value[12];
+        char downscaler_value[12];
+
+        snprintf(upscaler_value, sizeof(upscaler_value), "%d", upscaler);
+        snprintf(downscaler_value, sizeof(downscaler_value), "%d", downscaler);
+        upscaler_value[sizeof(upscaler_value) - 1] = '\0';
+        downscaler_value[sizeof(downscaler_value) - 1] = '\0';
+
+        config_chain_t cfg = {
+            .psz_name = (char *) "upscaler",
+            .psz_value = upscaler_value,
+            .p_next = &(config_chain_t) {
+                .psz_name = (char *) "downscaler",
+                .psz_value = downscaler_value,
+            },
+        };
+
+        struct vlc_gl_filter *scale_filter =
+            vlc_gl_filters_Append(vgl->filters, "pl_scale", &cfg);
+        if (!scale_filter)
+            msg_Warn(gl, "Could not load pl_scale");
+    }
+
     /* The renderer is the only filter, for now */
     struct vlc_gl_filter *renderer_filter =
         vlc_gl_filters_Append(vgl->filters, "renderer", NULL);
@@ -241,10 +269,14 @@ int vout_display_opengl_SetViewpoint(vout_display_opengl_t *vgl,
     return vlc_gl_renderer_SetViewpoint(vgl->renderer, p_vp);
 }
 
-void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t *vgl,
-                                              float f_sar)
+void vout_display_opengl_SetOutputSize(vout_display_opengl_t *vgl,
+                                       unsigned width, unsigned height)
 {
-    vlc_gl_renderer_SetWindowAspectRatio(vgl->renderer, f_sar);
+    int ret = vlc_gl_filters_SetOutputSize(vgl->filters, width, height);
+    /* The renderer, last filter in the chain, necessarily accepts the new
+     * output size */
+    assert(ret == VLC_SUCCESS);
+    (void) ret;
 }
 
 void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,


=====================================
modules/video_output/opengl/vout_helper.h
=====================================
@@ -34,6 +34,12 @@
 #ifdef HAVE_LIBPLACEBO
 #include "../libplacebo/utils.h"
 
+#define UPSCALER_TEXT "OpenGL upscaler"
+#define UPSCALER_LONGTEXT "Upscaler filter to apply during rendering"
+
+#define DOWNSCALER_TEXT "OpenGL downscaler"
+#define DOWNSCALER_LONGTEXT "Downscaler filter to apply during rendering"
+
 
 #if PL_API_VER >= 10
 #define add_desat_params() \
@@ -51,6 +57,13 @@
 #endif
 
 #define add_glopts_placebo() \
+    set_section(N_("Scaling"), NULL) \
+    add_integer("pl-upscaler", SCALE_BUILTIN, UPSCALER_TEXT, \
+                UPSCALER_LONGTEXT) \
+        change_integer_list(scale_values, scale_text) \
+    add_integer("pl-downscaler", SCALE_BUILTIN, DOWNSCALER_TEXT, \
+                DOWNSCALER_LONGTEXT) \
+        change_integer_list(scale_values, scale_text) \
     set_section(N_("Colorspace conversion"), NULL) \
     add_integer("rendering-intent", pl_color_map_default_params.intent, \
                 RENDER_INTENT_TEXT, RENDER_INTENT_LONGTEXT) \
@@ -95,8 +108,8 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl);
 
 int vout_display_opengl_SetViewpoint(vout_display_opengl_t *vgl, const vlc_viewpoint_t*);
 
-void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t *vgl,
-                                              float f_sar);
+void vout_display_opengl_SetOutputSize(vout_display_opengl_t *vgl,
+                                       unsigned width, unsigned height);
 
 void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
                                   unsigned width, unsigned height);


=====================================
modules/video_output/win32/glwin32.c
=====================================
@@ -231,7 +231,7 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
         const int width  = place.width;
         const int height = place.height;
         vlc_gl_Resize (sys->gl, width, height);
-        vout_display_opengl_SetWindowAspectRatio(sys->vgl, (float)width / height);
+        vout_display_opengl_SetOutputSize(sys->vgl, width, height);
         vout_display_opengl_Viewport(sys->vgl, place.x, place.y, width, height);
         sys->area.place_changed = false;
     }


=====================================
src/test/list.c
=====================================
@@ -56,6 +56,8 @@ int main (void)
     vlc_list_init(&head);
     vlc_list_foreach(elem, &head, node)
         assert(0); /* No iteration on an empty list */
+    vlc_list_reverse_foreach(elem, &head, node)
+        assert(0); /* No iteration on an empty list */
     assert(vlc_list_is_empty(&head));
 
     vlc_list_init(&head); /* List can be reinitialized */
@@ -64,6 +66,10 @@ int main (void)
     vlc_list_foreach(elem, &head, node)
         assert(elem->i == 1), count++;
     assert(count == 1);
+    count = 0;
+    vlc_list_reverse_foreach(elem, &head, node)
+        assert(elem->i == 1), count++;
+    assert(count == 1);
 
     back = make_elem(2);
     vlc_list_append(back, &head);
@@ -71,6 +77,10 @@ int main (void)
     vlc_list_foreach(elem, &head, node)
         assert(elem->i == count + 1), count++;
     assert(count == 2);
+    count = 0;
+    vlc_list_reverse_foreach(elem, &head, node)
+        assert(elem->i == 2 - count), count++;
+    assert(count == 2);
 
     vlc_list_prepend(make_elem(3), &head);
     vlc_list_remove(head.prev); /* remove number 2 */
@@ -87,6 +97,17 @@ int main (void)
     }
     assert(vlc_list_is_empty(&head));
 
+    vlc_list_prepend(make_elem(3), &head);
+    vlc_list_reverse_foreach(elem, &head, node)
+    {
+        vlc_list_remove(&elem->node);
+        free(elem);
+    }
+    assert(vlc_list_is_empty(&head));
+
+    /*
+     * Create a list from 10 to 30, inserting the 10 last element first
+     */
     for (int i = 20; i < 30; i++)
         vlc_list_append(make_elem(i), &head);
     for (int i = 19; i >= 10; i--)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f5b6d9d3467373af2338c37d046f945cedae4be1...5e14e1ed68275d6394b2c795657503777ddaf837

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f5b6d9d3467373af2338c37d046f945cedae4be1...5e14e1ed68275d6394b2c795657503777ddaf837
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list