Skip to content

Commit

Permalink
Use noncustom kernel when possible in bicubic and bilinear
Browse files Browse the repository at this point in the history
`descale.Decustom` init is slow and AFAICT it's only being used for
symmetry with `resize2.Custom`, which itself was introduced to enable
setting `blur` (am I missing something else?). If that's the
case, then everything is being made slower just for the (probably) few
cases of blur usage. This hurts the native-res plugin especially.

With this change, things work like so:

1. If descaling, always use `descale.Debicubic`/`descale.Debilinear`.
  They support `blur` so there should be no need for custom kernels.
2. If scaling/resampling, use `resize2.Bicubic`/`resize2.Bilinear` if
  `blur` is not set to the default of 1.0. This isn't here to speed
  anything up, rather it just seems like a good idea to use the plugin's
  available filters when possible instead of custom ones.
3. Otherwise, use the slower custom kernels since blur is needed and not
  provided by the plugin.

This only targets bicubic and bilinear since these are the most popular
descale kernels. With this, native-res execution
(height [502, 999], step size 1, Catrom) goes from ~3 minutes to ~30
seconds. If we like this approach and it works well then we can bring it
to the other kernels.
  • Loading branch information
sgt0 committed Nov 24, 2024
1 parent b04b604 commit 4acca74
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
39 changes: 36 additions & 3 deletions vskernels/kernels/bicubic.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from __future__ import annotations

from math import sqrt
from typing import Any
from typing import Any, override

from vstools import CustomValueError, inject_self
from vstools import CustomValueError, core, inject_self, vs

from .complex import CustomComplexKernel
from .helpers import bic_vals, poly3
Expand Down Expand Up @@ -36,12 +36,15 @@ class Bicubic(CustomComplexKernel):
:param c: C-param for bicubic kernel
"""

descale_function = core.lazy.descale.Debicubic # type: ignore[assignment]

def __init__(self, b: float = 0, c: float = 1 / 2, **kwargs: Any) -> None:
self.b = b
self.c = c
super().__init__(**kwargs)

@inject_self.cached
@override
def kernel(self, *, x: float) -> float:
x, b, c = abs(x), self.b, self.c

Expand All @@ -54,11 +57,41 @@ def kernel(self, *, x: float) -> float:
return 0.0

@inject_self.cached.property
def kernel_radius(self) -> int: # type: ignore
@override
def kernel_radius(self) -> int: # type: ignore[override]
if (self.b, self.c) == (0, 0):
return 1
return 2

@inject_self
@override
def scale_function( # type: ignore[override]
self, clip: vs.VideoNode, width: int | None = None, height: int | None = None, *args: Any, **kwargs: Any
) -> vs.VideoNode:
# If using the default blur, then remove it and use resize2's kernel
# implementation which has a faster init time.
if kwargs.get("blur", 1.0) == 1.0:
kwargs.pop("blur", None)
return core.resize2.Bicubic(clip, width, height, *args, **kwargs)

# Otherwise, fall back to the slower custom kernel implementation.
kwargs.pop("filter_param_a", None)
kwargs.pop("filter_param_b", None)
return super().scale_function(clip, width, height, *args, **kwargs)

resample_function = scale_function # type: ignore[assignment]

@override
def get_params_args(
self, is_descale: bool, clip: vs.VideoNode, width: int | None = None, height: int | None = None, **kwargs: Any
) -> dict[str, Any]:
args = super().get_params_args(is_descale, clip, width, height, **kwargs)
return (
args | {"b": self.b, "c": self.c}
if is_descale
else args | {"filter_param_a": self.b, "filter_param_b": self.c}
)


class BSpline(Bicubic):
"""Bicubic b=1, c=0"""
Expand Down
21 changes: 19 additions & 2 deletions vskernels/kernels/various.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from __future__ import annotations

from math import cos, exp, log, pi, sqrt
from typing import Any
from typing import Any, override

from vstools import inject_self
from vstools import core, inject_self, vs

from .complex import CustomComplexKernel, CustomComplexTapsKernel
from .helpers import sinc
Expand Down Expand Up @@ -62,12 +62,29 @@ def kernel(self, *, x: float) -> float:
class Bilinear(CustomComplexKernel):
"""Bilinear resizer."""

descale_function = core.lazy.descale.Debilinear # type: ignore[assignment]
_static_kernel_radius = 1

@inject_self.cached
@override
def kernel(self, *, x: float) -> float:
return max(1.0 - abs(x), 0.0)

@inject_self
@override
def scale_function( # type: ignore[override]
self, clip: vs.VideoNode, width: int | None = None, height: int | None = None, *args: Any, **kwargs: Any
) -> vs.VideoNode:
# If using the default blur, then remove it and use resize2's kernel
# implementation which has a faster init time.
if kwargs.get("blur", 1.0) == 1.0:
kwargs.pop("blur", None)
return core.resize2.Bilinear(clip, width, height, *args, **kwargs)

# Otherwise, fall back to the slower custom kernel implementation.
return super().scale_function(clip, width, height, *args, **kwargs)

resample_function = scale_function # type: ignore[assignment]

class Lanczos(CustomComplexTapsKernel):
"""
Expand Down

0 comments on commit 4acca74

Please sign in to comment.