Log in

View Full Version : z.lib resizers for AviSynth+


Pages : 1 2 3 4 5 6 7 [8]

poisondeathray
22nd October 2024, 15:47
It's all over with anything less than sse4.1, running in both Windows and Wine.

I get same results in windows that I did before, with sse3 or otherwise

hello_hello
22nd October 2024, 17:55
I get same results in windows that I did before, with sse3 or otherwise

Well the plot thickens. Maybe there's something the z.lib resizers don't like about my AMD 7900X CPU and VirtualBox is pretending it's a different one, or something.....

Native Linux VapourSynth (MX Linux)
https://i.imgur.com/sV0S64Z.png

Windows VapourSynth running in VirtualBox (Windows 11)
https://i.imgur.com/6xshfuJ.png

import vapoursynth as vs
core = vs.core
import CropResize as cr
import RGBColor as rgb
import HistoTop as ht

clip = core.std.BlankClip(format=vs.YUV420P10)
clip = core.std.BlankClip(clip, color=rgb.RGBColor(clip, 'red', matrix=1))
clip = core.resize.Spline36(clip, 240,240)

clipA = ht.HistoTop(core.resize.Bicubic(clip, format=vs.YUV420P8)).text.Text("BlankClip")

clipB = core.resize.Bicubic(clip, matrix_in_s="2020cl", transfer_in_s="2020_10", primaries_in_s="2020", \
range_in_s="limited", matrix_s="rgb", transfer_s="linear", primaries_s="xyz", range_s="full", format=vs.RGB48)
clipB = core.resize.Bicubic(clipB, matrix_in_s="rgb", transfer_in_s="linear", primaries_in_s="xyz", \
range_in_s="full", matrix_s="709", transfer_s="709", primaries_s="709", range_s="limited", format=vs.YUV420P16)
clipB = ht.HistoTop(core.resize.Bicubic(clipB, format=vs.YUV420P8)).text.Text("VapourSynth (ag=true)")

clipC = core.resize.Bicubic(clip, matrix_in_s="2020cl", transfer_in_s="2020_10", primaries_in_s="2020", \
range_in_s="limited", matrix_s="rgb", transfer_s="linear", primaries_s="xyz", range_s="full", format=vs.RGB48, \
approximate_gamma=False)
clipC = core.resize.Bicubic(clipC, matrix_in_s="rgb", transfer_in_s="linear", primaries_in_s="xyz", \
range_in_s="full", matrix_s="709", transfer_s="709", primaries_s="709", range_s="limited", format=vs.YUV420P16, \
approximate_gamma=False)
clipC = ht.HistoTop(core.resize.Bicubic(clipC, format=vs.YUV420P8)).text.Text("VapourSynth (ag=false)")

clipD = cr.CropResize(clip, 0,0, ColorConvert="FC", ColorMode="2020-709")
clipD = ht.HistoTop(core.resize.Bicubic(clipD, format=vs.YUV420P8)).text.Text("FMTConv")

clip = core.std.StackHorizontal([clipA, clipB, clipC, clipD])
clip.set_output()

poisondeathray
22nd October 2024, 18:32
No idea. You can also try testing core.std.SetMaxCPU("blah") for the vpy version . Both the vapoursynth core.resize and avsresize also have "cpu_type" parameters too to control for zimg/z.lib specifically instead of globally for the script

hello_hello
22nd October 2024, 19:15
I'm not sure what values VapourSynth accepts for cpu_type (the Resizer documentation doesn't specify) so I tried the values listed in the AVSResize docs. Anything above "avx512f" on the list produces an error:
vapoursynth.Error: Resize error: bad value: cpu_type
Values from "avx512f" down fix the problem, with the exception of "avx_e".

I haven't tested the Windows version of VapourSynth yet, only Linux, but I tested AVSResize running in Wine, and once again setting the correct cpu_type fixes the problem. CPU types such as "avx512_snc" that produce an error in VapourSynth don't do so for AVSResize though. Instead the output simply goes back to what it was originally (incorrect).

For some reason the cpu_type argument only seems to be needed when converting from RGB to YUV.

AVSResize

clipB = clip.ConvertBits(Bits)\
.z_ConvertFormat(colorspace_op="2020:2020:2020:limited=>rgb:linear:xyz:full", pixel_type=RGBType)\
.z_ConvertFormat(colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type=YUVType, cpu_type="avx512f")

VapourSynth

clipB = core.resize.Bicubic(clip, matrix_in_s="2020cl", transfer_in_s="2020_10", primaries_in_s="2020", \
range_in_s="limited", matrix_s="rgb", transfer_s="linear", primaries_s="xyz", range_s="full", format=vs.RGB48)
clipB = core.resize.Bicubic(clipB, matrix_in_s="rgb", transfer_in_s="linear", primaries_in_s="xyz", \
range_in_s="full", matrix_s="709", transfer_s="709", primaries_s="709", range_s="limited", format=vs.YUV420P16, cpu_type="avx512f")

https://i.imgur.com/NFMSPqL.png

For the record, the color's probably a tad different compared to the screenshot in my previous post as I think I used matrix=9 instead of matrix=1 when creating the blank clip this time.
clip = core.std.BlankClip(clip, color=rgb.RGBColor(clip, 'red', matrix=9))

_Al_
22nd October 2024, 22:05
On windows 10, using vapoursynth R62, (it seams R62 version resize does not have approximate_gamma argument yet, so no ClipC,
using this script (no dependent modules, except histogram and fmtConv):

import vapoursynth as vs
from vapoursynth import core

def histo_top(clip, subtitle):
if not hasattr(core, 'hist'):
raise AttributeError('vapoursynth histogram plugin is not loaded, nhttps://github.com/dubhater/vapoursynth-histogram')
clip = core.resize.Bicubic(clip, format=vs.YUV420P8)
clip = clip.std.Transpose().std.FlipHorizontal() # turn right
clip = core.hist.Classic(clip).std.Transpose().std.FlipVertical() # turn left
return clip.text.Text(subtitle)

clip = core.std.BlankClip(color=(255, 0, 0))
clip = core.resize.Bicubic(clip, width=240, height=240, format=vs.YUV420P10, matrix_s="709")

clipA = histo_top(clip, subtitle="BlankClip")

clipB = core.resize.Bicubic(clip, matrix_in_s="2020cl", transfer_in_s="2020_10", primaries_in_s="2020",
range_in_s="limited", matrix_s="rgb", transfer_s="linear", primaries_s="xyz", range_s="full", format=vs.RGB48)
clipB = core.resize.Bicubic(clipB, matrix_in_s="rgb", transfer_in_s="linear", primaries_in_s="xyz",
range_in_s="full", matrix_s="709", transfer_s="709", primaries_s="709", range_s="limited", format=vs.YUV420P16)
clipB = histo_top(clipB, subtitle="ag=default(true?)")

# clipC = core.resize.Bicubic(clip, matrix_in_s="2020cl", transfer_in_s="2020_10", primaries_in_s="2020",
# range_in_s="limited", matrix_s="rgb", transfer_s="linear", primaries_s="xyz", range_s="full", format=vs.RGB48,
# approximate_gamma=False)
# clipC = core.resize.Bicubic(clipC, matrix_in_s="rgb", transfer_in_s="linear", primaries_in_s="xyz",
# range_in_s="full", matrix_s="709", transfer_s="709", primaries_s="709", range_s="limited", format=vs.YUV420P16,
# approximate_gamma=False)
# clipC = histo_top(clipC, subtitle="VapourSynth (ag=false)")

if not hasattr(core, 'fmtc'):
raise AttributeError('FMTConv plugin is not loaded, https://github.com/EleonoreMizo/fmtconv/releases')
clipD = core.fmtc.resample(clip, css="444")
clipD = core.fmtc.matrix(clipD, mat="2020", fulls=False, fulld=True)
clipD = core.fmtc.transfer(clipD, transs="1886", transd="Linear")
clipD = core.fmtc.primaries(clipD, prims="2020", primd="709")
clipD = core.fmtc.transfer(clipD, transs="Linear", transd="1886")
clipD = core.fmtc.matrix(clipD, mat="709", fulls=True, fulld=False)
clipD = core.fmtc.resample(clipD, css="420")
clipD = histo_top(clipD, subtitle="FMTConv")

clip = core.std.StackHorizontal([clipA, clipB, clipD])
clip.set_output()
https://imgur.com/a/VlWs4nZ

Jamaika
22nd October 2024, 22:39
I've been compiling various projects for a long time.
Does ffmpeg + avisynth + avsresize make sense? Or is this creation a piece of junk? I won't deny that it's hard to compile under Windows and I had to correct errors.
https://www.sendspace.com/file/9ar08u

tormento
23rd October 2024, 18:02
There is a strange bug that I can't really understand.

I was playing with some resize scripts and one arose to my mind. Something like:

SetMemoryMax()
SetCacheMode(0)
SetFilterMTMode("DEFAULT_MT_MODE", 2)
LoadPlugin("D:\Eseguibili\Media\DGDecNV\DGDecodeNV.dll")
Import("D:\Eseguibili\Media\StaxRip\Apps\Plugins\AVS\DehaloAlpha\Dehalo_alpha.avsi")
Import("D:\Eseguibili\Media\StaxRip\Apps\Plugins\AVS\Dither\mt_xxpand_multi.avsi")
Import("D:\Eseguibili\Media\StaxRip\Apps\Plugins\AVS\FineDehalo\FineDehalo.avsi")
DGSource("M:\In\Shangri-La frontier vol 1-4 ~931p BDJP\1-01.dgi", dn_enable=3, dn_strength=0.04, dn_cstrength=0.02, dn_quality="best")
AiUpscale(Factor=1, CResample="KrigBilateral", Mode="LineArt", OutDepth=16)
Spline64ResizeMT(1656,932,threads=1)
FineDehalo(rx=2.0, ry=2.0, thmi=80, thma=128, thlimi=50, thlima=100, darkstr=0.6, brightstr=1.0, showmask=0, contra=0.0, excl=true)
libplacebo_Deband(iterations=5,temporal=false)
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion")
Prefetch(2,6)

The idea was to upscale the chroma to 444 before resizing.

It ended with a grey line at the bottom of the screen (zoom the image)

https://i.ibb.co/Ytc3RSZ/Shangri-La01.png (https://ibb.co/30p7rbz)

i.e. no chroma information.

I have commented every single line and arrived to a very simple scripts, such as

Source()
z_ConvertFormat(pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion")

And I had the very same result.

I tried to debug the error.

At first, I saw that changing the last line to

fmtc_resample(css="420",kernel="spline64")

works perfectly.

Later, I changed the last line to

z_ConvertFormat(pixel_type="YUV420P10")

and the grey line disappeared too.

Eventually, I have noticed that the other z.lib resamplers, such as Lanczos, doesn't show the same issue.

What's wrong with Spline64 in z.lib? Why does it work with fmtc_resample?

poisondeathray
24th October 2024, 02:01
Source()
z_ConvertFormat(pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion")

And I had the very same result.



The following looks ok to me, no grey line . How about you ?


ColorbarsHD(1920,1080)
ConvertToYV12()
FlipVertical()
z_ConvertFormat(pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion")


If you have problem , post avs+ version, avsresize version

Or can you provide a source/script combination that can produce the problem

FranceBB
24th October 2024, 10:23
Oh crap.
Well, there's a good news and a bad news.
The "bad news" is that I can reproduce the issue.
The "good news" is that you stumbled upon a bug in the AVX assembly code that none of my production servers at work use.


To make it appear more obvious I used the following code:

source=ColorBars(500, 960, pixel_type="YV16").Crop(0, 0, -0, -940)


z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx")
avx=last


z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx2")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx2")
avx2=last

StackHorizontal(avx, avx2)


Here you can see how the output produced by the AVX assembly code (left) has the issue, while the one produced by AVX2 (right) doesn't:

https://i.imgur.com/zppCvjo.png


I also tried all the other assemblies and luckily enough the issue was present only in the AVX code path.
This is the full test with plain C++, AVX, AVX2, AVX512:

source=ColorBars(500, 960, pixel_type="YV16").Crop(0, 0, -0, -940)

z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="none")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="none")
Subtitle("C++")
cpp=last

z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx")
Subtitle("AVX")
avx=last


z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx2")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx2")
Subtitle("AVX2")
avx2=last

z_ConvertFormat(source, pixel_type="YUV444P16", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx512f")
z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion", cpu_type="avx512f")
Subtitle("AVX512")
avx512=last

StackVertical(cpp, avx, avx2, avx512)

https://i.imgur.com/HaPcZNH.png


I opened a bug in the sekrit's zimg repository here: https://github.com/sekrit-twc/zimg/issues/209

FranceBB
25th October 2024, 15:17
Sekrit fixed it.
Turns out, it was used by AVX only capable CPUs but it was actually part of the SSE2 code path.
Anyway this is the commit with the fix https://github.com/sekrit-twc/zimg/commit/034b7cf5339e576080e61fd53f566387687ff4d6
Full SSE2 assembly code by Sekrit https://github.com/sekrit-twc/zimg/blob/master/src/zimg/resize/x86/resize_impl_sse2.cpp

To test Sekrit's fix, I grabbed the StvG's avsresize source code from here https://codeberg.org/StvG/avsresize and I linked against the zimg master, the graphedit master and the Avisynth master (the Ferenc & Stephen repository) and compiled a debug build.

Link (avsresize r25 + Spline64 SSE2 bugfix x64 MSVC): https://github.com/user-attachments/files/17523207/avsresize.zip

Sekrit's fix works. :)

https://i.imgur.com/nbOjC4F.png

Now we just need StvG to build a new version of avsresize using this new version of zimg and release avsresize r26. ;)
Please do not use my debug build for anything other than testing. Wait for StvG to release the final version.

tormento
25th October 2024, 23:27
Link (avsresize r25 + Spline64 SSE2 bugfix x64 MSVC)
Getting

Script error: There is no function named 'z_ConvertFormat'.

for

z_ConvertFormat(pixel_type="YUV420P10", resample_filter_uv="Spline64", dither_type="error_diffusion")

FranceBB
26th October 2024, 00:07
You're missing the Microsoft C++ Redistributable.
You can install them one by one from the Microsoft website or get the unofficial AIO (all in one) package from here https://github.com/abbodi1406/vcredist/releases/

tormento
26th October 2024, 18:47
You're missing the Microsoft C++ Redistributable.
You linked the debug dlls not the standard ones.

StvG
27th October 2024, 15:14
avsresize_r25a (https://codeberg.org/StvG/avsresize/releases):
- zimg 2aed91a


@hello_hello, you can also try this build (https://files.catbox.moe/2e14q0.7z) if the other r25a build still give you different output in Wine.

Jamaika
27th October 2024, 16:07
plugins/libzimg/zimg++.hpp:333:8: warning: extra tokens at end of '#endif' directive [-Wendif-labels]
333 | #endif ZIMG_GRAPHENGINE_API // ZIMG_GRAPHENGINE_API
| ^~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp:1067:27: error: 'ZIMG_TRANSFER_PROPHOTORGB' was not declared in this scope
1067 | { "prophoto", ZIMG_TRANSFER_PROPHOTORGB},
| ^~~~~~~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp:1085:25: error: 'ZIMG_PRIMARIES_PROPHOTO' was not declared in this scope
1085 | { "prophoto", ZIMG_PRIMARIES_PROPHOTO },
| ^~~~~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp: In function 'AVSValue {anonymous}::create_resize(AVSValue, void*, IScriptEnvironment*)':
plugins/avsresize.cpp:1472:29: error: 'struct zimgxx::zfilter_graph_builder_params' has no member named 'scene_referred'
1472 | params.graph_params.scene_referred = args[22].AsBool(false);
| ^~~~~~~~~~~~~~

StvG
27th October 2024, 17:25
plugins/libzimg/zimg++.hpp:333:8: warning: extra tokens at end of '#endif' directive [-Wendif-labels]
333 | #endif ZIMG_GRAPHENGINE_API // ZIMG_GRAPHENGINE_API
| ^~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp:1067:27: error: 'ZIMG_TRANSFER_PROPHOTORGB' was not declared in this scope
1067 | { "prophoto", ZIMG_TRANSFER_PROPHOTORGB},
| ^~~~~~~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp:1085:25: error: 'ZIMG_PRIMARIES_PROPHOTO' was not declared in this scope
1085 | { "prophoto", ZIMG_PRIMARIES_PROPHOTO },
| ^~~~~~~~~~~~~~~~~~~~~~~
plugins/avsresize.cpp: In function 'AVSValue {anonymous}::create_resize(AVSValue, void*, IScriptEnvironment*)':
plugins/avsresize.cpp:1472:29: error: 'struct zimgxx::zfilter_graph_builder_params' has no member named 'scene_referred'
1472 | params.graph_params.scene_referred = args[22].AsBool(false);
| ^~~~~~~~~~~~~~

There is zimg.patch in the release archive.

FranceBB
28th October 2024, 15:59
avsresize_r25a (https://codeberg.org/StvG/avsresize/releases):
- zimg 2aed91a


Thank you for the official build! :D
I can confirm that the issue is solved.

https://i.imgur.com/irYBS2B.png

hello_hello
2nd November 2024, 09:51
avsresize_r25a (https://codeberg.org/StvG/avsresize/releases):
- zimg 2aed91a


@hello_hello, you can also try this build (https://files.catbox.moe/2e14q0.7z) if the other r25a build still give you different output in Wine.

Thanks. I tried them both but the result is still the same. I need to use the cpu_type argument for the RGB to YUV part of the conversion to get the expected result when approximate_gamma is true.

z_ConvertFormat(colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type=YUV420P16, cpu_type="avx512f")

It doesn't seem to be a Wine issue as such though, as the behavior is the same for the native Linux flavor of VapourSynth and it's resizers. Possibly something to do with my AMD 7900X CPU??

Cheers.

FranceBB
4th November 2024, 14:36
Hey hello_hello, I'm trying to reproduce this on Windows Server 2019 Standard x64 running on an Intel Xeon Gold 6238R which supports AVX512 natively.
Unfortunately (or should I say "fortunately" in this case) I can't reproduce as the C++, AVX, AVX2 and AVX512 conversions all produce identical results.


source=ColorBars(500, 960, pixel_type="YUV444P16").Crop(0, 0, -0, -940).ConvertYUVtoXYZ().ConverttoPlanarRGB()

z_ConvertFormat(source, colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type="YUV420P16", cpu_type="none")
Subtitle("C++")
cpp=last

z_ConvertFormat(source, colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type="YUV420P16", cpu_type="avx")
Subtitle("AVX")
avx=last

z_ConvertFormat(source, colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type="YUV420P16", cpu_type="avx2")
Subtitle("AVX2")
avx2=last

z_ConvertFormat(source, colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type="YUV420P16", cpu_type="avx512f")
Subtitle("AVX512")
avx512=last

StackVertical(cpp, avx, avx2, avx512)



https://i.imgur.com/2lOESqu.png


In other words, it doesn't seem to be an issue within avsresize, at least not in the Avisynth version running on bare metal hardware.

hello_hello
4th November 2024, 17:22
Hey hello_hello, I'm trying to reproduce this on Windows Server 2019 Standard x64 running on an Intel Xeon Gold 6238R which supports AVX512 natively.
Unfortunately (or should I say "fortunately" in this case) I can't reproduce as the C++, AVX, AVX2 and AVX512 conversions all produce identical results.

If it's a CPU related issue it looks like it's an AMD one. Or an AMD/Linux one. The same problem exists for both AVSResize running in Wine and the native Linux VapourSynth resizers.

If Avisynth and/or VapourSynth are running on Windows 11 in VirtualBox there's no issue with approximate_gamma=true. I don't know much about emulation but apparently VirtualBox pretends Windows is running on an Intel chipset, although Device Manager correctly identifies the AMD Ryzen 9 7900x CPU. I haven't tried adding cpu_type to z_ConvertFormat running on Windows though as it's not needed and I rarely run anything in Windows/VirtualBox anyway.

As a side note I was reading a review regarding the newer AMD CPUs and SMT (hyperthreading). It mentioned disabling SMT can sometimes improve performance a little for specific workloads, so I thought I'd try it. The Avisynth script I used for testing included some fairly slow denoising and I was encoding with x264, all running in Wine. I wasn't expecting much of a change, but disabling SMT increased encoding speed by roughly 30% (~25 fps to ~33fps), CPU usage increased from 50-60% to 90%, and the CPU also ran about 7 degrees cooler with SMT disabled. I ran the test twice for each, obviously rebooting in between to disable/enable SMT. Maybe that's a Wine or Linux issue too. I haven't run the test again with the native Linux Vapoursynth and x264 to see if the result is similar, but I probably will sometime soon, just out of curiosity.

StvG
4th November 2024, 22:28
@hello_hello, you can report to zimg.

Emulgator
4th November 2024, 22:43
Maybe just one codepath, and maybe compiler dependent, so dependent on build version ?
IIRC qyot27 found such dependency on another occasion.

takla
5th November 2024, 23:41
As a side note I was reading a review regarding the newer AMD CPUs and SMT (hyperthreading). It mentioned disabling SMT can sometimes improve performance a little for specific workloads, so I thought I'd try it. The Avisynth script I used for testing included some fairly slow denoising and I was encoding with x264, all running in Wine. I wasn't expecting much of a change, but disabling SMT increased encoding speed by roughly 30% (~25 fps to ~33fps), CPU usage increased from 50-60% to 90%, and the CPU also ran about 7 degrees cooler with SMT disabled. I ran the test twice for each, obviously rebooting in between to disable/enable SMT. Maybe that's a Wine or Linux issue too. I haven't run the test again with the native Linux Vapoursynth and x264 to see if the result is similar, but I probably will sometime soon, just out of curiosity.

If your CPU wasn't thermal or power throttling SMT=Off shouldn't get more fps.

hello_hello
6th November 2024, 17:51
@hello_hello, you can report to zimg.

Done. https://github.com/sekrit-twc/zimg/issues/211

hello_hello
17th November 2024, 21:09
According to the response to my question here (https://github.com/sekrit-twc/zimg/issues/211#issuecomment-2463684750), there's no need to use an intermediate RGB clip when converting color with AVSResize (at least for standard matrix/primaries conversions). Therefore converting from rec.2020 to rec.709 this way isn't necessary:

z_ConvertFormat(colorspace_op="2020:2020:2020:limited=>rgb:linear:xyz:full", pixel_type="RGBP16")
z_ConvertFormat(colorspace_op="rgb:linear:xyz:full=>709:709:709:limited", pixel_type="YUV420P16")

And it's okay to do it like this:

z_ConvertFormat(colorspace_op="2020:2020:2020=>709:709:709", pixel_type="YUV420P16")

Is that correct?? I feel like it shouldn't be after using the first method for so long.

StvG
19th November 2024, 13:04
This way is also worse if the intermediate RGB is 16-bit and not float. If the intermediate RGB is float (RGBPS), then both methods has identical output - your choice which to use (I always use the one line method).

hello_hello
20th November 2024, 17:17
Thanks!

hello_hello
8th December 2024, 05:48
StvG,

I know I asked about 32 bit float handling a while ago, but I'm still not 100% sure how to correctly convert to float and back.

For an 8 bit limited range clip, the frame property becomes full range if I do this:

ConvertBits(32)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8)

ConvertBits can change the frame property back to limited range though, and the result is exactly the same:

ConvertBits(32)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=false, fulld=false)

However as you previously said zimg assumes 32-bit float is full range, I'm wondering if I should do it like this. According to Compare() the output isn't the same, but in my head at least, it seems to be the technically correct method. Would that assumption be correct?

Cheers.

ConvertBits(32, fulls=false, fulld=true)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=true, fulld=false)

DTL
8th December 2024, 12:57
If all used equations are not dependent on the range mapping - the frame properties range mapping hints do nothing in float samples format processing. So if the result is the same - you can pass any range mapping to float processing. But you need to check the before and after range mapping to be equal. Some plugins may depend on the black (and all other levels position/mapping).

So if you send narrow-float (shifted black) to convert and use narrow-float to narrow-integer convert back it will work. Many plugins may assume float always uses black mapped to 0.0f and nominal white mapped to 1.0f. (Also zero UV to 0.0f). But some may use any other like 0..max_int mapped to 0.0f..max_int_as_float.

"For an 8 bit limited range clip, the frame property becomes full range if I do this:

ConvertBits(32)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8)"

You use 3 filters in a chain - first you can start to look where your range mapping property switched from narrow/limited to full. Maybe after the first ConvertBits(32) filter.

hello_hello
8th December 2024, 15:26
You use 3 filters in a chain - first you can start to look where your range mapping property switched from narrow/limited to full. Maybe after the first ConvertBits(32) filter.

It's definitely z_ConvertFormat writing "full" to frame properties. Avisynth's ConvertBits is happy for float to be either full or limited range.
I hunted around some more and I'm pretty sure for my example above, converting limited range integer to full range float before z_ConvertFormat is the correct way to do it, as zimg always assumes float is full range (either that or let zimg do the conversion).

https://github.com/sekrit-twc/zimg/issues/134
https://forum.doom9.org/showthread.php?p=1927024#post1927024

I think the same applies to FMTConv. The help file doesn't specifically say float is full range, but it does say the fulls and fulld arguments have no meaning for float data.

These produce the same result (8 bit limited range input):

A = ConvertBits(32, fulls=false, fulld=true)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=true, fulld=false)

B = z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg", bit_depth=32)\
.ConvertBits(8, fulls=true, fulld=false)

Compare(A,B)

The output here is very close, but not exactly the same. Maybe a rounding difference when converted back to 8 bit?

A = ConvertBits(32, fulls=false, fulld=true)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=true, fulld=false)

B = z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg", bit_depth=32)\
.z_ConvertFormat(bit_depth=8)

Compare(A,B)

tormento
8th December 2024, 22:43
I think the same applies to FMTConv
I deeply encourage you to use FMTconv when dithering down, instead of AVS+ implicits or z_img, at least for its wider dithering choices and resilience of some of them (i.e. 8) to codec encoding.

StvG
9th December 2024, 01:15
StvG,

I know I asked about 32 bit float handling a while ago, but I'm still not 100% sure how to correctly convert to float and back.

For an 8 bit limited range clip, the frame property becomes full range if I do this:

ConvertBits(32)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8)

ConvertBits can change the frame property back to limited range though, and the result is exactly the same:

ConvertBits(32)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=false, fulld=false)

However as you previously said zimg assumes 32-bit float is full range, I'm wondering if I should do it like this. According to Compare() the output isn't the same, but in my head at least, it seems to be the technically correct method. Would that assumption be correct?

Cheers.

ConvertBits(32, fulls=false, fulld=true)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=true, fulld=false)

The latest example is the correct one.

If you will use z_ConvertFormat in already converted 32-bit environment you have to be sure that the range is [0,1] (full) before the z_ConvertFormat call.

The output here is very close, but not exactly the same. Maybe a rounding difference when converted back to 8 bit?

A = ConvertBits(32, fulls=false, fulld=true)\
.z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg")\
.ConvertBits(8, fulls=true, fulld=false)

B = z_ConvertFormat(colorspace_op="170m:601:170m=>470bg:601:470bg", bit_depth=32)\
.z_ConvertFormat(bit_depth=8)

Compare(A,B)

Yes, the difference is due to rounding diff.

hello_hello
23rd March 2025, 02:04
Is it expected behavior for AVSResize to flip the image when pixel shifting rather than duplicate the edge pixels?
I realize these aren't exactly examples of real world pixel shifting, but it wasn't what I expected so I thought I'd ask.
Using a 640x480 source:

Spline36Resize(640,480,0,0,680,520)
https://i.ibb.co/35g1x3dL/A.png

z_Spline36Resize(640,480,0,0,680,520)
https://i.ibb.co/Q7DbBnwv/B.png

Spline36Resize(640,480,-40,0,640,520)
https://i.ibb.co/TD6NqNvN/C.png

z_Spline36Resize(640,480,-40,0,640,520)
https://i.ibb.co/HppPqS0z/D.png

StvG
23rd March 2025, 06:58
Is it expected behavior for AVSResize to flip the image when pixel shifting rather than duplicate the edge pixels?

Yes, this is the zimg behavior.

StvG
31st August 2025, 03:11
New version: avsresize r26 (https://codeberg.org/StvG/avsresize/releases).

Jamaika
31st August 2025, 05:09
I don't know why it doesn't work in C++17. Too modern, remains old.
plugins/avsresize/avsresize.cpp:1390:82: error: no matching function for call to 'std::basic_string_view<char>::basic_string_view(const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&)'
1390 | const std::string_view dst_matrix(match[5].first, match[5].second);
| ^

StvG
31st August 2025, 12:32
I don't know why it doesn't work in C++17. Too modern, remains old.

C++20 is required.

tormento
1st September 2025, 10:24
C++20 is required.
I hope not to annoy you with the request that I am making to many developers.

When you have time, could you try a Intel compiler build?

StvG
1st September 2025, 17:38
I hope not to annoy you with the request that I am making to many developers.

When you have time, could you try a Intel compiler build?

Release files:
- x64 binary is compiled with Intel C++ Compiler 2025.
- x86 binary is compiled with clang-cl.

Here you can download x64 binaries compiled with MSVC and clang-cl (https://files.catbox.moe/tgjh5o.7z), if you want to benchmark the different binaries.

tormento
1st September 2025, 19:36
Release files:
- x64 binary is compiled with Intel C++ Compiler 2025.
- x86 binary is compiled with clang-cl.

Here you can download x64 binaries compiled with MSVC and clang-cl, if you want to benchmark the different binaries.

Sorry but I can't understand.

You write Intel + clang and then the files are MSVC + clang.

You mean that the x64 release file is ICC already?

StvG
1st September 2025, 19:54
Sorry but I can't understand.

You write Intel + clang and then the files are MSVC + clang.

You mean that the x64 release file is ICC already?

Release is avsresize_26.7z. When you extract it - there are x64 (64-bit) and x86 (32-bit) binaries. Binary file means "avsresize.dll".
x64 binary - avsresize.dll (64-bit) is compiled with Intel C++ Compiler 2025 (icx, not icc because icc is the signature of the old Intel C++ Compilers).
x86 binary - avsresize.dll (32-bit) is compiled with clang-cl because the Intel C++ Compilers supports only 64-bit.

The additional files I shared in my previous post are only 64-bit - when you extract the archive, you will see two folders "avsresize_r26_cl" (compiled with MSVC) and "avsresize_r26_clang" (compiled with clang-cl).

I hope it's clear now.

tormento
1st September 2025, 20:42
I hope it's clear now.
It happens something really strange with your builds.

Usually, for my old CPU (i7-2600k w/AVX only), the speed order is:

ICX > MSVC > CLANG > GCC

but with your plugin and a madeup script

ColorBarsHD(3840, 2160)
z_ConvertFormat(chromaloc_op="top_left=>left",pixel_type="RGBP16", colorspace_op="2020:st2084:2020:limited=>rgb:st2084:2020:full", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)
z_ConvertFormat(pixel_type="yuv444ps", colorspace_op="rgb:std-b67:2020:full=>2020:std-b67:2020:limited", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)
z_ConvertFormat(resample_filter="spline64",dither_type="error_diffusion",pixel_type="YUV420P10")
Prefetch(4)

I have

clang 6.904 fps
ICX 5.603 fps
MSVC 5.722 fps

and it's really unusual. :eek:

StvG
2nd September 2025, 14:56
It's unsual for you but it doesn't mean something is wrong. You should understand that the compilers aren't static. Even the same compiler with same settings but different version can produce binaries with different performance (speed and memory).

From my quick tests both icx and clang-cl are on par.

tormento
4th September 2025, 12:20
From my quick tests both icx and clang-cl are on par.
Thank you for your time and effort ;)

Sharc
15th September 2025, 08:10
It's still r21.7 in the Avisynth wiki......