Skip to content

Commit

Permalink
Use noncustom kernel when possible
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.

With this, native-res execution (height [502, 999], step size 1, Catrom)
goes from ~3 minutes to ~30 seconds.
  • Loading branch information
sgt0 committed Nov 24, 2024
1 parent b04b604 commit 57b31cb
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 9 deletions.
22 changes: 19 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,16 @@ class Bicubic(CustomComplexKernel):
:param c: C-param for bicubic kernel
"""

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

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 +58,23 @@ 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

@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
9 changes: 8 additions & 1 deletion vskernels/kernels/complex.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from math import ceil
from typing import TYPE_CHECKING, Any, SupportsFloat, TypeVar, Union, cast
from typing import TYPE_CHECKING, Any, SupportsFloat, TypeVar, Union, cast, override

from stgpytools import inject_kwargs_params
from vstools import (
Expand Down Expand Up @@ -261,6 +261,13 @@ def __init__(self, taps: float, **kwargs: Any) -> None:
def kernel_radius(self) -> int: # type: ignore
return ceil(self.taps)

@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 | {'taps': self.taps} if is_descale else args | {'filter_param_a': self.taps}


ComplexScalerT = Union[str, type[ComplexScaler], ComplexScaler]
ComplexKernelT = Union[str, type[ComplexKernel], ComplexKernel]
22 changes: 20 additions & 2 deletions vskernels/kernels/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from stgpytools import CustomValueError, KwargsT, inject_self
from inspect import Signature

from vstools import vs, core
from typing import Any, Protocol
from vstools import GenericVSFunction, vs, core
from typing import Any, Protocol, override
from .abstract import Kernel

from typing import TypeVar
Expand All @@ -20,6 +20,13 @@ def __call__(self, *, x: float) -> float:


class CustomKernel(Kernel):
_no_blur_scale_function: GenericVSFunction | None = None
"""
Optional scale function that will be used when scaling without blur. This is
useful for cases where this function is more performant than the custom
kernel.
"""

def kernel(self, *, x: float) -> float:
raise NotImplementedError

Expand All @@ -37,14 +44,25 @@ def kernel(*, x: float) -> float:
return self.kernel, support

@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 a no-blur scale function is defined and the default blur is being
# used, then remove the parameter and use the given scale function.
if self._no_blur_scale_function and kwargs.get("blur", 1.0) == 1.0:
kwargs.pop("blur", None)
return self._no_blur_scale_function(clip, width, height, *args, **kwargs)

# Otherwise, fall back to the slower custom kernel implementation.

kernel, support = self._modify_kernel_func(kwargs)

clean_kwargs = {
k: v for k, v in kwargs.items()
if k not in Signature.from_callable(self._modify_kernel_func).parameters.keys()
# Remove params that won't be recognized by `resize2.Custom`.
and k not in ('filter_param_a', 'filter_param_b')
}

return core.resize2.Custom(clip, kernel, int(support), width, height, *args, **clean_kwargs)
Expand Down
8 changes: 7 additions & 1 deletion vskernels/kernels/spline.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from math import comb
from typing import Any

from vstools import inject_self
from vstools import core, inject_self

from .complex import CustomComplexTapsKernel
from .helpers import poly3
Expand Down Expand Up @@ -106,6 +106,8 @@ def __init__(self, **kwargs: Any) -> None:
class Spline16(NaturalSpline):
"""Spline16 resizer."""

descale_function = core.lazy.descale.Despline16
_no_blur_scale_function = core.lazy.resize2.Spline16
_static_kernel_radius = 2

_static_coeffs = [
Expand All @@ -117,6 +119,8 @@ class Spline16(NaturalSpline):
class Spline36(NaturalSpline):
"""Spline36 resizer."""

descale_function = core.lazy.descale.Despline36
_no_blur_scale_function = core.lazy.resize2.Spline36
_static_kernel_radius = 3

_static_coeffs = [
Expand All @@ -129,6 +133,8 @@ class Spline36(NaturalSpline):
class Spline64(NaturalSpline):
"""Spline64 resizer."""

descale_function = core.lazy.descale.Despline64
_no_blur_scale_function = core.lazy.resize2.Spline64
_static_kernel_radius = 4

_static_coeffs = [
Expand Down
11 changes: 9 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,9 +62,12 @@ def kernel(self, *, x: float) -> float:
class Bilinear(CustomComplexKernel):
"""Bilinear resizer."""

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

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

Expand All @@ -76,10 +79,14 @@ class Lanczos(CustomComplexTapsKernel):
:param taps: taps param for lanczos kernel
"""

descale_function = core.lazy.descale.Delanczos # type: ignore[assignment]
_no_blur_scale_function = core.lazy.resize2.Lanczos

def __init__(self, taps: float = 3, **kwargs: Any) -> None:
super().__init__(taps, **kwargs)

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

Expand Down

0 comments on commit 57b31cb

Please sign in to comment.