From 14373685801564c8701eb78df58817713ff5ddb2 Mon Sep 17 00:00:00 2001 From: Etienne Charland Date: Tue, 1 Dec 2015 22:33:05 -0500 Subject: [PATCH] Released v1.3 --- README.md | 86 +++++++++--------- Release/ChangeLog.txt | 10 +- Release/ReadMe.txt | 38 +++++--- Release/Shader.dll | Bin 164352 -> 163840 bytes Shaders/ColorMatrix/ColorMatrix.avsi | 8 +- Shaders/Super-xBR/super-xbr.avsi | 60 ++++++------ Shaders/SuperRes/SuperRes.avsi | 85 +++++++++-------- Src/AviSynthShader.vcxproj | 8 +- Src/AviSynthShader.vcxproj.filters | 8 +- ...ertFromFloat.cpp => ConvertFromShader.cpp} | 28 +++--- ...ConvertFromFloat.h => ConvertFromShader.h} | 8 +- ...ConvertToFloat.cpp => ConvertToShader.cpp} | 28 +++--- Src/{ConvertToFloat.h => ConvertToShader.h} | 10 +- Src/ExecuteShader.cpp | 2 +- Src/Init.cpp | 47 ++++------ 15 files changed, 216 insertions(+), 210 deletions(-) rename Src/{ConvertFromFloat.cpp => ConvertFromShader.cpp} (82%) rename Src/{ConvertFromFloat.h => ConvertFromShader.h} (84%) rename Src/{ConvertToFloat.cpp => ConvertToShader.cpp} (85%) rename Src/{ConvertToFloat.h => ConvertToShader.h} (79%) diff --git a/README.md b/README.md index a73a97a..37a940f 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ -# AviSynth Shader v1.2.2 +# AviSynth Shader v1.3 Download here >> This plugin allows running HLSL pixel shaders within AviSynth. This gives access to various HLSL filters that haven't been programmed in AviSynth. -This implementation allows running several shaders in a row. Shader() returns a clip containing commands, and each subsequent to Shader() adds a line to that command chain clip. You must call ExecuteShader() to execute the chain of commands. You must also call ConvertToFloat() before and ConvertFromFloat() at the end. +This implementation allows running several shaders in a row. Shader() returns a clip containing commands, and each subsequent to Shader() adds a line to that command chain clip. You must call ExecuteShader() to execute the chain of commands. You must also call ConvertToShader() before and ConvertFromShader() at the end. The following example will run Diff1 and Diff2 on the clip before returning a Merge of both results. (these shader names are fictive, you have to use real shaders!) - ConvertToFloat() - input - Shader("Diff1.cso", output=2) - Shader("Diff2.cso", output=3) - Shader("Merge.cso", clip1=2, clip2=3, output=1) - ShaderExecute(input) - ConvertFromFloat() + ConvertToShader() + Input + Shader("Diff1.cso", Output=2) + Shader("Diff2.cso", Output=3) + Shader("Merge.cso", Clip1=2, Clip2=3, Output=1) + ShaderExecute(last, Input, PrecisionIn=1, Precision=3, PrecisionOut=1) + ConvertFromShader() ## Syntax: -#### ConvertToFloat(input, convertYuv, precision) +#### ConvertToShader(Input, Precision) Converts a YV12, YV24 or RGB32 clip into a wider frame containing UINT16 or half-float data. Clips must be converted in such a way before running any shader. @@ -26,51 +26,47 @@ Converts a YV12, YV24 or RGB32 clip into a wider frame containing UINT16 or half Arguments: -convertYuv: True to convert RGB data to YUV on the CPU. If false, YUV data will be copied as-is and can then be converted with a shader. Default=false. +Precision: 1 to convert into BYTE, 2 to convert into UINT16, 3 to convert into half-float. Default=1 (conversion can be done on the GPU) -precision: 1 to convert into BYTE, 2 to convert into UINT16, 3 to convert into half-float. Default=2 - -#### ConvertFromFloat(input, format, convertYuv, precision) +#### ConvertFromShader(Input, Format, Precision) Convert a half-float clip into a standard YV12, YV24 or RGB32 clip. Arguments: -format: The video format to convert to. Valid formats are YV12, YV24 and RGB32. Default=YV12. - -convertYuv: True to convert YUV data to RGB on the CPU. If false, you already ran a shader to convert to YUV and the data will be copied as-is. Default=false. +Format: The video format to convert to. Valid formats are YV12, YV24 and RGB32. Default=YV12. -precision: 1 to convert into BYTE, 2 to convert into UINT16, 3 to convert into half-float. Default=2 +Precision: 1 to convert into BYTE, 2 to convert into UINT16, 3 to convert into half-float. Default=1 -#### Shader(input, path, entryPoint, shaderModel, param1-param9, clip1-clip9, width, height) +#### Shader(Input, Path, EntryPoint, ShaderModel, Param1-Param9, Clip1-Clip9, Output, Width, Height) Runs a HLSL pixel shader on specified clip. You can either run a compiled .cso file or compile a .hlsl file. Arguments: -input: The first input clip. +Input: The first input clip. -path: The path to the HLSL pixel shader file to run. +Path: The path to the HLSL pixel shader file to run. -entryPoint: If compiling HLSL source code, specified the code entry point. +EntryPoint: If compiling HLSL source code, specified the code entry point. -shaderModel: If compiling HLSL source code, specified the shader model. Usually PS_2_0 or PS_3_0 +ShaderModel: If compiling HLSL source code, specified the shader model. Usually PS_2_0 or PS_3_0 -param0-param8: Sets each of the shader parameters. +Param0-Param8: Sets each of the shader parameters. Ex: "float4 p4 : register(c4);" will be set with Param4="1,1,1,1f" End each value with 'f'(float), 'i'(int) or 'b'(bool) to specify its type. Param0 corresponds to c0, Param1 corresponds to c1, etc. If setting float or int, you can set a vector or 2, 3 or 4 elements by separating the values with ','. -clip1-clip9: The index of the clips to set into this shader. Input clips are defined when calling ExecuteShader. Clip1 sets 's0' within the shader, while clip2-clip9 set 's1' to 's8'. The order is important. +Clip1-Clip9: The index of the clips to set into this shader. Input clips are defined when calling ExecuteShader. Clip1 sets 's0' within the shader, while clip2-clip9 set 's1' to 's8'. The order is important. Default for clip1 is 1, for clip2-clip9 is 0 which means no source clip. -output: The clip index where to write the output of this shader, between 1 and 9. Default is 1 which means it will be the output of ExecuteShader. If set to another value, you can use it as the input of another shader. The last shader in the chain must have output=1. +Output: The clip index where to write the output of this shader, between 1 and 9. Default is 1 which means it will be the output of ExecuteShader. If set to another value, you can use it as the input of another shader. The last shader in the chain must have output=1. -width, height: The size of the output texture. Default = same as input texture. +Width, Height: The size of the output texture. Default = same as input texture. -#### ShaderExecute(cmd, clip1-clip9, precision) +#### ExecuteShader(cmd, Clip1-Clip9, Precision) Executes the chain of commands on specified input clips. @@ -78,16 +74,16 @@ Arguments: cmd: A clip containing the commands returned by calling Shader. -clip1-clip9: The clips on which to run the shaders. +Clip1-Clip9: The clips on which to run the shaders. -precision: 1 to execute with 8-bit precision, 2 to execute with 16-bit precision, 3 to execute with half-float precision +Precision: 1 to execute with 8-bit precision, 2 to execute with 16-bit precision, 3 to execute with half-float precision. Default=2 -precisionIn: 1 if input clips are BYTE, 2 if input clips are UINT16, 3 if input clips are half-float. Default=2 +PrecisionIn: 1 if input clips are BYTE, 2 if input clips are UINT16, 3 if input clips are half-float. Default=1 -precisionOut: 1 to get an output clip with BYTE, 2 for UINT16, 3 for half-float. Default=2 +PrecisionOut: 1 to get an output clip with BYTE, 2 for UINT16, 3 for half-float. Default=1 -#### SuperRes(input, passes, strength, softness, upscalecommand, srcMatrix601, convert) +#### SuperRes(Input, Passes, Strength, Softness, Upscalecommand, SrcMatrix601, PrecisionIn) In Shaders\SuperRes\SuperRes.avsi. Thanks to Shiandow for writing this great code! @@ -97,20 +93,20 @@ Supported video formats: YV12, YV24, RGB24 and RGB32. Arguments: -passes: How many SuperRes passes to run. Default=1. +Passes: How many SuperRes passes to run. Default=1. -strength: How agressively we want to run SuperRes, between 0 and 1. Default=1. +Strength: How agressively we want to run SuperRes, between 0 and 1. Default=1. -softness: How much smoothness we want to add, between 0 and 1. Default=0. +Softness: How much smoothness we want to add, between 0 and 1. Default=0. -upscalecommand: An upscaling command that must contain offset-correction. Ex: """nnedi3_rpow2(2, cshift="Spline16Resize")""" +Upscalecommand: An upscaling command that must contain offset-correction. Ex: """nnedi3_rpow2(2, cshift="Spline16Resize")""" -srcMatrix601: If true, the color matrix will be changed from Rec.601 to Rec.709 while running SuperRes. This avoids having to apply ColorMatrix separately. Default=false. +SrcMatrix601: If true, the color matrix will be changed from Rec.601 to Rec.709 while running SuperRes. This avoids having to apply ColorMatrix separately. Default=false. -convert: Whether to call ConvertToFloat and ConvertFromFloat() within the shader. Set to false if input is already converted. Default=true. +PrecisionIn: 0 to call ConvertToShader and ConvertFromShader within the shader. 1-3 if the source is already converted. Default=0. -#### Super-xBR(input, edgeStrength, weight, thirdPass, convert) +#### Super-xBR(Input, EdgeStrength, Sharpness, ThirdPass, Convert) In Shaders\Super-xBR\super-xbr.avsi. Thanks to Shiandow for writing this great code! @@ -120,18 +116,18 @@ Supported video formats: YV12, YV24, RGB24 and RGB32. Arguments: -edgeStrength: Value between 0 and 5 specifying the strength. Default=1. +EdgeStrength: Value between 0 and 5 specifying the strength. Default=1. -weight: Value between 0 and 1.5 specifying the weight. Default=1. +Sharpness: Value between 0 and 1.5 specifying the weight. Default=1. -thirdPass: Whether to run a 3rd pass. Default=true. +ThirdPass: Whether to run a 3rd pass. Default=true. -convert: Whether to call ConvertToFloat and ConvertFromFloat() within the shader. Set to false if input is already converted. Default=true. +PrecisionIn: 0 to call ConvertToShader and ConvertFromShader within the shader. 1-3 if the source is already converted. Default=0. #### ColorMatrix601to709(input) -In Shaders\ColorMatrix\ColorMatrix.avsi. Thanks to Shiandow for writing this great code! +In Shaders\ColorMatrix\ColorMatrix.avsi Converts color matrix from Rec.601 to Rec.709 with 16 bit depth to avoid banding. Source can be YV12, YV24, RGB24 or RGB32. diff --git a/Release/ChangeLog.txt b/Release/ChangeLog.txt index 6305d57..79972b7 100644 --- a/Release/ChangeLog.txt +++ b/Release/ChangeLog.txt @@ -1,11 +1,17 @@ Version 1.3: December 1st 2015 - SuperRes distortion problems fixed. Colors should now be accurate. - Shaders now use PrecisionIn=1 and convert frames to 16-bit on the GPU +- 10% performance increase and lowered memory usage - Fixed SuperRes when using Softness parameter -- Shader.dll now treats overflow coordinates with CLAMP +- Overflow coordinates now use 'clamp' - Fixed distortion line at the right and bottom of Super-xBR - Fixed sub-pixel shift with Super-xBR when ThirdPass=false -- 10% performance increase and lowered memory usage +- Super-xBR 'weight' argument renamed to 'sharpness' +- ConvertToFloat renamed to ConvertToShader, ConvertFromFloat renamed to ConvertFromShader +- ConvertToShader/ConvertFromShader, removed convertYuv argument +- ConvertToShader/ConvertFromShader, precision default is now 1 +- All arguments now start with a uppercase letter +- Added PrecisionIn argument to SuperRes and Super-xBR. Set to 0 to call ConvertToShader within the shader; set to 1-3 if it is already converted. Version 1.2.2: November 29th 2015 - For SuperRes, HLSL Bicubic downscaler is broken and has been disabled. Downscaling is now done in AviSynth diff --git a/Release/ReadMe.txt b/Release/ReadMe.txt index 82056e5..4cfdada 100644 --- a/Release/ReadMe.txt +++ b/Release/ReadMe.txt @@ -1,9 +1,19 @@ AviSynthShader by Etienne Charland Provides a bridge between AviSynth and HLSL pixel shaders for high bit depth processing on the GPU. +Ex: NNEDI3+SuperRes +SuperRes(2, .42, 0, """nnedi3_rpow2(2, nns=4, cshift="Spline16Resize", threads=2)""") +Ex: Super-xBR+SuperRes +ConvertToShader(Precision=2) +SuperRes(2, 1, 0, """SuperXBR(PrecisionIn=2)""", PrecisionIn=2) +ConvertFromShader("YV12", Precision=2) -SuperRes(input, passes, strength, softness, upscalecommand, srcMatrix601, convert) + + +SuperRes(Input, Passes, Strength, Softness, Upscalecommand, SrcMatrix601, PrecisionIn) + +In Shaders\SuperRes\SuperRes.avsi. Thanks to Shiandow for writing this great code! Enhances upscaling quality. @@ -11,23 +21,24 @@ Supported video formats: YV12, YV24, RGB24 and RGB32. Arguments: -passes: How many SuperRes passes to run. Default=1. +Passes: How many SuperRes passes to run. Default=1. -strength: How agressively we want to run SuperRes, between 0 and 1. Default=1. +Strength: How agressively we want to run SuperRes, between 0 and 1. Default=1. -softness: How much smoothness we want to add, between 0 and 1. Default=0. +Softness: How much smoothness we want to add, between 0 and 1. Default=0. -upscalecommand: An upscaling command that must contain offset-correction. Ex: """nnedi3_rpow2(2, cshift="Spline16Resize")""" +Upscalecommand: An upscaling command that must contain offset-correction. Ex: """nnedi3_rpow2(2, cshift="Spline16Resize")""" -srcMatrix601: If true, the color matrix will be changed from Rec.601 to Rec.709 while running SuperRes. This avoids having to apply ColorMatrix separately. Default=false. +SrcMatrix601: If true, the color matrix will be changed from Rec.601 to Rec.709 while running SuperRes. This avoids having to apply ColorMatrix separately. Default=false. -convert: Whether to call ConvertToFloat and ConvertFromFloat() within the shader. Set to false if input is already converted. Default=true. +PrecisionIn: 0 to call ConvertToShader and ConvertFromShader within the shader. 1-3 if the source is already converted. Default=0. +Super-xBR(Input, EdgeStrength, Sharpness, ThirdPass, Convert) -Super-xBR(input, edgeStrength, weight, thirdPass, convert) +In Shaders\Super-xBR\super-xbr.avsi. Thanks to Shiandow for writing this great code! Doubles the size of the image. Produces a sharp result, but with severe ringing. @@ -35,19 +46,21 @@ Supported video formats: YV12, YV24, RGB24 and RGB32. Arguments: -edgeStrength: Value between 0 and 5 specifying the strength. Default=1. +EdgeStrength: Value between 0 and 5 specifying the strength. Default=1. -weight: Value between 0 and 1.5 specifying the weight. Default=1. +Sharpness: Value between 0 and 1.5 specifying the weight. Default=1. -thirdPass: Whether to run a 3rd pass. Default=true. +ThirdPass: Whether to run a 3rd pass. Default=true. -convert: Whether to call ConvertToFloat and ConvertFromFloat() within the shader. Set to false if input is already converted. Default=true. +PrecisionIn: 0 to call ConvertToShader and ConvertFromShader within the shader. 1-3 if the source is already converted. Default=0. ColorMatrix601to709(input) +In Shaders\ColorMatrix\ColorMatrix.avsi + Converts color matrix from Rec.601 to Rec.709 with 16 bit depth to avoid banding. Source can be YV12, YV24, RGB24 or RGB32. @@ -60,7 +73,6 @@ Converts color matrix from Rec.709 to Rec.601 with 16 bit depth to avoid banding - Shaders are written by Shiandow and are available here https://github.com/zachsaw/MPDN_Extensions/ diff --git a/Release/Shader.dll b/Release/Shader.dll index 6c597df1277d034a6082896f3095dcd2d935dcd8..7683eff4c5d6c8dc2aad440f38aa1464aca3ff0f 100644 GIT binary patch delta 19288 zcmZvD3tUav_xM?-hg+^(B$ZGpuaf(Io%_g8^2n4Zp%NmEM<}mBQ6X1`IoKHEF^pk` z5f?EJBF`D)F<-Coj0qhGCW`uuLw0kqzR10ln8{(MuVoXskb$ASN|6J*{ep?XfLJs`@$k@IHR8`%Ts@lV9#p)#3Xk$ag#_ z-F82%>g=JsxvWe$orN-^?}JQOIGmsAS=p()FDt7$+wczsy@-)OvhC?9PfE#anj=XT zVv_lxO~T<0Kd*@upNE?m@cFVyNE^y>D%PD&;bhD!*gUuh+n)7yxuiQFOS+d<>XH(j zEWA$QH+gkO^f@mLl=JT1Dy-|h`v=QxbA4&|(%5L6MQQ8^mz)bI{bXz$!+-9b>bV}r zIONY?@Q!rPn{X(YR+{9Q4t7BvKDTKfn8P1z+QY4RhiJZe(=NP^)Z5c^Fqjg9rIUi} zix{Rfc7QEbcC?yJD2*K|Y(`AcaY)wvd||1ry9r?HfsWR?2DVp z+~Apgt?WENn0@aTXbAX9b!XRpg(0VapbkOofrCsqcd(t zH%}3M)AJX?g5326hT#>>IyIQHP}FXXo(~TXMJ3|GgZ)bNbmiPjV{Y0`pNe^f42)16 z!p{qDE8|g~EniYnIm^f9neE=+z9T#u*exo)u2aWh{U+jI6L4_b%j6WH54IfpYu-2< z*jR}T?3a>k^K>NmrU-%9E;`<&&JB^x55!!w_0LOAzyXDCB9Smt#^n1T`m~4^wng&U zojK_*-5AC-a2I}e=KvVWpXs~|?%IcTaRi?z8R&xM!C{6+pl}kU2d$VN59+36*&)OHMfz^O)bN ztD5YCXsE;#M?$deG*aAzUHm%vXrCI#1lGjH~<^Rk`nJ)N4?p4c=-t`X9bb{VP8(PQrHm)jm^m)(!UY zz;)&)7(!jO0}Zv0jSZ-NjkT4HwcD;*Ust!OTm$!ajWw!dy-|jXL5Dy!MP6Tiktvvs z`GenKn%DE!|Fv~w@~N15YWD0xd^F5^MF_fGJ@w`M$JDIi#&_iV^HY?5{0Z}0YfLb_ ztsijJm#CWa#U?*~kfo($QN3tyH-59FEx*Xpk{wjfe_~Ow?dtgp7L`Q!T_k&o z61x-8L_`d?wq)o1&QG?gBz>KDFA;wN8GW4yZxQhiGTwQ@`$R`I+x>*D3DsFxd6(}S zoy>chWqf&bvw&cD;f176xlU;5`Die<(!5<%u=#kNgmQ%E3 z;5%qp9N)C(DEOYA)Kdw!_{}~2!~-LSb)2+2dL98-!XN1s1|#{JUgME6uy-^bD{(!y+^r0DIXCRsjd0H%aNFroRTdcj6=%sk)yQzlH;FLnpQ8Y3&aH~r-V&|`LejE zCb>hfo-l+z7H5MReqi4Me4gu@fn!DW%fR}weiY-=e+8R6gx}oX%$5)4tNRDC^1=33 z{r{Chjs4|N4ZwYS)UZ?p{Nmv+-~?YVA{IvQCr5M!HUDHp+lcNv874`H-A0`uSx{hj z%fbIiwwFRHN=eRv6rp|>U~z0!wNKDHGdbTWlm&aZD=X_#vLk7)bo-{vb^sOp;ZZ%B-Lm6IO`YO;+W#44gzo>D&d7wH zFbD};6Wku|VY4XWJBoPEiO7Bmvh1Pw5LWV;W7vj+DGd- z?sTcM4MSL2ir}?~zgdvdJrBwME$NadDZAuP|3zW9&NFAE0&DD< zWxl{xujOYf8|pL26B9*xuGo4>gfaZBWt(9OU+__YE6B}<86Sb zD#nE&;(GXR=ZDkQY|618o8iP5X&4H|GwRwE+RiRD$F2vpHmtHCt ziuft3!XS`ey(*&VladB(7yj%jWyd|V9a?u(^`h=Xjx>AmXk4Eq7jd<+YH%?m4!ID; zhpY~3`6=R#Nih|vvBk&`+iWtai-0g9^@V2q;?-eNHxzV=@x#dpCi}tF9RWJ~ZTEeQ>^_!9SgNr+aTQvpszw1A3j5wJ(-;x{o zO-{wC*S`W;ietK3c+H>xy0!Gj360F|eErwH(y!hkYIxahzlhSeh+`i#SW4U*ws=Xh zt*7*;Al(l6If=r4K5_S8srOs{Ui_Zj-65X8vwIWt;0w!BA%wqPK7d_3ou6Ock?+4p z1GDY(_oRUIYIdUCN9-?ifA4_9!Qa{6mcP3HU+JwejZ{DW_JQ}% z$3rS2rK8@WKjBj=-h&ML`idVs@eCYy_&?!iFnD1p!Lkv{K`a-sJi_uE3-bed-Vc1n zkv8xnKjX-$aBMHevI@)BSgNpG!}1%JzpzMtWMrW~@}n!eNkfM>sx#cawz4@3P3$|4 zjf7U)QW^<&@XdmY{4mTN9Qg}}0PQ~;<~)JJPQ}XTYlb>EN36sai&q&YK`7z3p00)hzT`|846}cE zrU+o7J?h6!z{XDHd;HkZKI`mWH~5&3yimrvbNu7Wf&68xb}Q#C_qy;)FWO-qAN_N0 z)?nZ#Tn({*@$*@Leth1giEz_??~(-IKYZQgIS|fgUzr3C`KwoWNa8=Z`YG(UdtF-# z(3aowOD^tj-|M|0i%-2y;3xaj>umt`^IkV+U>ur%b2a4i{ThzBdtC@n7BBMdkgv1HQGp)oca`;6J~g2V42T z2Symr4|%W+j@e&5h+tv0y-RHv3sdazbz=bf+V?)jO@vzi#^I6E`N?K@Za?$nzPkjv z;5}O|Soi~f_Fx?h|L{+1r#FnO9?MHCh>}UL_+V*?#UINv#J5A%0ne^tG7|RuM;6lU z^?ywU=w%=IcSn}RV033kK(~dSfVnZqmSdsym99eTw5)N#m7e_Rf5-Qm*P(IED=<%U zMx`PHgAr-;The+bsc4ozllKtAmaQkAyvP#$mSqI8>E}7)kS0l_;vUu(e$y_pKl?+}3rchZxNn#f^*CHl$y~S6 zo|2@L97sq=7KZSb-u#UT!#PJf{IaS$l)&^=c1VT}#2Zse=uI#eONC}6h=sARjTEt9 zhvP)&2H_o|$58$08-W+j8Tbm(__o0{-&y2CH|W&frx8$`sA5Ve*>^ zPstHC2m&Ly=>~y;k4KA>t1fww@8!s^5ynwYT1g@@cd#})fTD7kExGgXd=Dif+##UZ z@^?_L$O3oh0$TEwJM@h>dsd8=AH+!X9)*~(rB&G+n29Ce+5XQ!hEcuPOyxM#o>{_l(duJ~rYVHARZJI?RAGRu(VQjCQRzxyBFSqCi&{-Sitd3aW@Vk$kuS|b zRp$~PDJ%%e&cLf9zK_H_C~geu`Oh$C9)!1uVPvNix(7BH?sOrt@8R&R$Mm{hUN58R=N7aAm4$R>N*Kr8SiC)&UwSV`jjAq@T?Q~hym1IZnK z=na=iSO9bmpPJ}!q~_q&qxzM@L02Iv8>e^{Pld7)Io?1hsx8S4fP2k8NI+K1;8Z_l z2rb8RWgV+>G~b;sOHLA2BF1(tHMQhMUTf~nv=$M6 zmAP}tROW~*(LXY5Rm1W1w2%=eULqwqe!_07roQlyPhn+jUPw+G!9a!uK|Z`kE(E~{ zxKFybgPD*-wzb2NmyzGvL1*~9qIG*X2oOQeb$|gdlC%wmNSI3Ef}sX{NcRxnao$Hm zAR1x_8w%^1-=2w=rI=@U!J>}coO~4uU1i%EkP?c#dY$YHh4zH)2wBjIWOsx)pd$A> z!Z3&;(P1zdyerDX(CBcI><@?Tpdr78!)sVa?skH1P(Y-ep_F}|T0uHPkXzG-CR{Et zmyaWdyFs^3FA+gqMa<-f_7MFKffcTB~j2>2JkL>_d9_QpgrT~7MGeLy^Dm zHHrB50M64}k5}smlG+0l@IJ9o@PK^Z0~c)?dDH{;!A-JJ4&z}j@lwD&WO=MW8Gn)9 zO6bSF8c3EaAp$M@of6_<1;GymAuyRlQV>rDs$dB0BwJPJ?*^@>T( zrZ}OLtl*%HmmXQGko+mx!$BV?uK1h7A=~73!(G=zxP*sbs_Mq#w1=f>uaX24>1l>e z9cLl2YDwBdWVk^Y=#ij$VOw|_<gL@+~F@FXoQsPa&fY5^{2Om|#< z46QqB>G;!EQ~6j}@jtKeE6I;l740G|?Z_u=S&$chMc#QEtjy*X@{^Rq(Q@? z$6bkN!Pwm zn$5m+IO?7`-@N5`WN@eQ+Xw>Q-d!{M0js6@+CF%m6uq3-yhMi;m7~^3L1kTA;Y*}b zh4;Vh^5g=dPCGK_7btq5)YD~KKmz;W*}H&@><5J~k=*SEonRP|^oKC-YuGo3DQzP3 zA=>_QgH>erhgASi$eRHepE%Mr9@;|?iKE~(85a*B(oW|ZO_D)Y#zTMjxuQBA_5fQH z&405zk{o#-eSH?0p8!d0cv}*gh;g+(0gP~-%uj^2BsLN2NKb^J5KOKoLM9w0ra^cL zY02?H@P4x`^cWUTk#ylY2~L8qF>0Sr!bvP5tp{U(UQLn*V@P+9d4nMsdXbHTp{FG5 zKH4`y_=X6BVMLQk{Ctog3?==C;PI{?9}L0$`#IS$1W%-7B29*NaFBFM1{J1&>B*P~ zv?cSCp*LH5oDA3i?bz2c@*o)oc#S{qG;$u{Fh2PPxSC-IUCWe4R;K`g{v>KBw3Cjm zYBbJzk}?!#<8kowP*8Sb?$XuAfT*GS;E!st^(L>gbIaVrHhxk%>hQ$f6P1d26?7w0 zhv6LK$hu)r3>!#?;m{TrksFSxk0GhUQD-1?hC?IRHNe4w3eBYpNQW6s zl@fHg7p0h?{)gmcApUc*DgzC-kDSTCI0LqYiFUufcL z1k=VpyPT9T+V~9{7^DWB!R4uxROLiwAEdH$#3Ks^;Q=u;3%W@o@mlZNyjf&f7B0p^ z;x!iIaycPmVYtuWQ>aP&+0r-(=A0#~$6+kmO(MrZZ15uYcWpRV!r;B7%f3cwndIYf z5ZU1+Vp8kEFziWbHlHHw5)rbZH`UX_G1lE02Z6ZLUXDX+C6LH$JT#PKdNxeO&|900 z>sU^jjE9r(H90pP0&sf><6#PHBExcU;r}5Ea$qoCMy}>ynkkS~A3#XR$#S&8fyFes zj0?m~lIoZ~N7(ZgiQLH6y%;gJg)5QmNFhEVP9+FaMARBrYqZ#9DYkHngiioncreAN zga8Ei4ld?ZQNc4N&(GH96&@MVB0ZCjXZtHMe*y-y8nSi*49BzW`2_gJ`|;mz#CMRw zGID4l#QUmn&G7DqhnD3r%Br%R6i$=CNieFZ64%W6o^t|OGzmJh%q~(s2_{7L@WoX; zF3nI?(nJrBE8Ej#;bT1}4W32S9a2pl@;y(+O7JaYvT%>YO@`H&uiu#rds}uxp2Wmk zL1BX2K&>HokuABf8_rZDO@Um1zsd2bpoL@P->G zI6~e`N4K6xI?MnQWRejxU=p7EKhD6zaRzxl11h0O#etd7kws^}J{u-NK8gDf9%2R{ zpMyLt$*?)_3zSx<=fYipFNj|OR8iIfu)tOlPzXx{+Suq6WwtkEB_m#m@9`t?%LF}& z4;R83yoRLAhZ}8{l!{#chet*FE`aQ`6)i<8;T^hj;rDrXb}$*~!}FSzl}x~Tf*=cT z2%19s+Bf13Q&lF=e?prz4u|uin1c5x!Mg(2#TGBMy|nd}zBuZc-$B?+e2UQf^NFzt zrZkV8j|^OWo)0>9lAtHw6yctFNtzYoHccgci^YVB6hk;>+TRzW1x}NP#h{k*tLY9A zkL9zZa|whO$O#=PR>pbc&UC)IZ|}tTavpgujMRzo=R9V*F#n(&>=nd$%yD4^CnlKl zD0E@2I5AN{&1yS_mU|7ehLjNpvab zv>rSzLI&NCIlkHYaTr`%-hShlkFhYAVcJ&ybq%wXRv+Vz_M%@d;#c6VKPhO)u2KwW z`6O=%^pyU+ywM+SkfTfR)Zav2Ey4URo6NSs3D`lRmx4*E{HT%5mn>ciL0*3?Lst)G z1eWYt3Oe5kSMwM`mw)|BUM__WO*dj!%wJ;Nh2a&UW$=?bsb2wQQYG#qSK$AElzt3t zrA^;rdXw^xAw#-paU;(!q%9ATvV5FFS^P6wee(lui3tMkNghn?y)L~G-~aeGy#Hw> zcwtv(AnQf;@OXDPMnYDC9AAkHT8UTcHn+bNw{g>B&5M7;l}kzzbKlcs&MFK$<>bp% z5Z&nneu;Cb_zhNVOl>l*tJ(2}Ve;E1CFQU*O;8irYFxZP(hXl{;;FxBHO!In#f?4B zk}d?y(td9-MPv$r;nH7=8hL`qHG*kD64|o`On%8<;8-th*KOx98g=}!=x;~9AKuj6 z)?zxLCY{zo7uoY|4oAmhNXBd>f3Glzq_4$;>k8Sv7BZDQh6Y?2dgYS~Yq5cfUuDtj z&edZ*O3(9K!$B^tgFrWx5LIz`J)WtuU1xAnXinn1E&CJ4rw|b` z{s|6};ApLO%5NuR&PAo_ox_xR3R$H8258@67It>Me~Fhl6qt_B-hkQROLA}n^pTd& zp{5gqSS@L~5$|+Q$=;0+8nn^*O%<)uy!dBa);@Lq_*K0uMo18fN&QB+2nKR&6Q9rZpm0J}bYzBY8Bc%8<_zjPTsax>w+G)fo=ib9zwTAAhC&#eeaP7G}-Rby`$?>h2 z?lvRdpF^;;1hFoa#u4r3pzb)D=DJlvgo|DKmSJ)}O2AuBGAa8UbgiyoGej@cAaHqG zJ971Ni1sa^e7MDyzoncZ5!=wXZ%FJm_}y=IUgMx6uv#jwGbIQ;NdGUOv(zlo@N&rr z9mu>dppAFdap$ar&&b9vK;AS;K+ES#(CFjH^)DdA>o-I=rn?JS74F+1$4%NZw^5_n zWcF9^)X;l!BWCU-ddI2Vgaf#et2RRTTXMRST!`c({NWYZx)ZuJ`$|OC^>M3A5N?qh zJE61R3`C{YN$F8{()O3i(WewYQ;#M7yCAfy7lt?6>C%|`jz5$Rc}Be*w}MolqS2)X zV<638lksO=cgg5opz)cAqvI!V{05#c6THc`U65Tc8F|Go;Q0FanIpeGMd*m}uyN}Y z2!#`=u)3MT7_1cOJ@T6h6R~!RX@;5$qp+H6(+gdwmbO!MiQLJ8{d3&8+tYTVKpAS2 zBK(XYsX<`g?i38cP7m*b9^L{ofrUc5w*nm%8@`4=y;$W`!XJbWVRJ?ELwHpCCuPzx zLvhSoG0$$b$BUKtd38}m-Z$WjzmwSRaNti4Fu7WfHT=~@zQmywf<2w-gvk0n*?Abl z`bT8i5l8@C#qlHH>)~@Xxj`;w;y;iF$6-2N1=CKz6Bd6=Q4xO{p3w^F^&`YL$=USA z@ki}|3i2cT>ju{ee;%{}*Ma^lpa#Km`gn}xB^K!oa_>B>Yk33l%ki-W%XTc^-Kbc0 z0oJ$`)E|1|aDH5-P<`7igyd^5zn>DL`~te3#k;5r);q zi7>b}T7*HhdJ+29%0=i~+eL)3+F%h%YyCwisg)t5b{VR9;}Cyqnd6n?jz7;UsvM9Y z*h=ZxDpBq3;&wIu2aw6RcO z<3;R9ial1*AnfefGMtD0#2l&>e{6F8B3CFNd8impItpaRi!;?-=!0@S~zn(kJR zBUiw`pphUNz_7VFh;4gj}EMHUmCYh@6xb~!+Y`O-11-G$XB|O?Wd&cz5Q%3r&%L0Pn4qXXBAy3P~jFB7E&r=zro``@n4*|Wra4VsJ? zO2rkT+l%7*Hi(P&ul12r2Nh~PMTqM6pzZ3~7b3h_`$UA-Y9EO3QtfRKUZ}ky!n3vK zdWh3(`Ctg0;ET`bq_U|R?~~Klpj`p7p+oxC9>I!GDUx4Oa=?FSDNbGdEnki@$DjUu zRd`T>J;h(~AxeTMk8*eVrR*HV!3OV}3OaMyTer>%*s?9W;F`-iEFY{;Y!CQY6(DL8B9=&anl@slTE=g05RM`ex) z&YXaM(U9pR>IXISCHHQ@H$JVYoJL&5m$$*2g?$zKtLYoGeHDM-g_KqWgF>B}Ep)+d z=^(p`<=2VM^1~RAg=T?lH?}LW&>2)A?_eXy3bBO6fowLGA6)#sbKcIB%Aovbk)PJ* zAspkX;|`)fv#L1%90sVHeGjsAl_1-Q<>=vxF5TE~y~$M_+nvZXY=mc0cIKF@sU%v% z>V2?VugR09XHCtEojQ3UIi+R8yZR@wvS9qV{691Qw?rd;tBamXE^63T9@YMgtdP`d z*e(r{{j_X%FPGTClSQHUN&mE~TXY!yDylX9Jjj=kMI*#)K~`Q-rey~~RO;mX;EDOu z@`A^XpNh}XxE{fcf}DB>Po5M!ZF2t9(OC=uJ-ev2T>anjWGFM2e5z*^1qoBLMvtF{ zOPx0U?L-Gpb_!xf509NZbz){-+O*;S#rTdvT%6b$|BW7=keQc_+%c2#rp`*3Jbn`G z>ST$ZJSJ-b6_hzObE4c;DVV5eKq(t4s)mZXp`vN1Xd5cJhKe35y(Wy$RiupxQk}C zjn_)_$ECCIt1bz#u&ulzv1!6`iL|h?ZTu(|g^2%95Hk|n*|SJ{3+vZ9m$G3bpu~EF z&TbQ}Y)4Ht3Z!JQA3o^59Qsb1;_0Atw8vN)M{Kn^nspDj`3@@`^&qw@8+F95kRH)& zf4D>vqgfS#l4v%fAR1rM9wZF&A--^}Udu4S8?oF0CK1a7EDN!0!*UGEUs%4W2BscM z=exiR#4-nq=RIJiVYz{&>#x8Z#qt-Hlp0_bU|EmlG?ph=eC`9|k0oYsiX7)jdh}$E zf`vToiJ!;M0uz;&H8U@4B8{%18m;iWa^hw((f2DBzQ?Ax1>A8)GCe|Sp=gA7Wpnhu zLtezN5ne9x*gK?KEdCwZ9g>V7$c0_wV%~%>)PoNY?SxQn}yVA?L7X z3m5u=3qHL=y!)`Kf@-H0{s<{|Fhc4^T@X^Ca)fvkGkSy`2%{0=WSBUF_$zNF0igup zP=xdjKN6ug!fY3Q9zx1jjF9$Qf{@Btj*!ajwi+vRp!Eppz@H(cifl)SfcY9BHOszg z@}LhIz}39xf{ze37$A;3?Slr8+;#S3TrlJ=NsnVAe6dLd#UZ3U=;#N<9)TlWoY^jz z>tdaLmt4V~3Kx1gLaN#hgjCgIF8Iua{|6zW8Ri~Q_GMLl?>UkuMfzWtTFKrMn?%~}_Him+i(hT_LPwnLx{{|1Ei=!lSN!Xc!Z z^sOP&`=bPG(&e1)f^!g336$j;nU4~@m%B)-Ysdra5#VYbaKZ0f@K_D$Hh_(A!zLLy zfDIy*16T?R-acqt=!@@5M4vIbPg0#I4X}5A1QkTF6 zG#N4x|0ZQ3Lz)g^+d(=}#IqeF7bZJ9i=yyz=9GB0txxwUjBEfFD(&7Z@=ZJ&#g>tkSJ^ic_FZ>k=p7dNCubDJGK!vVpQ8A3AYg&Sqr$u;2$_*0)LZ z0_0fWR4OPRbGdm~qNz~VzgO4|m3NR=!&(2;@3XyqnxfF=SSSN(H0XUcO0olc(YC0% zWWeTkTI?V%;ys9M&;IKpLdobB?^q0f?Ewimce~#^NU!QP&Q=ZClYqIDuRqBANoE4u zwj~|pa-fs?J;I*?$=3;Npk!J5clxt;+LK2KIOKh;6F${A;UHK0Qzw+{#w@u}ZFW)| z`7#lE&Fn{hKq!eye3zOv#5s+v86uZYk4z_(_GdGlT0C~)L^H7UIpU~YHe+T>xoTX_ zu+Ie>oaE~%?~EhCm)Y;=)O40pr+-$9IhoJI`a_%2uO4kvX~IUO-D@XUWeb`uL7 z_1%B#v&e%aHk94ezruSkJ5a*PlPZRdU<19#$}Bdl)&Hb;(b43qEVi4(nF&QlSKP{C zGu#VSX+O~(*8ZdgokEwXTcO*jJECi)-=Tl3ml!%3`WU7gel$EY1R8r8#~Q1QkBxqu zl^e$`;jVE(mUPP&%N;8!6^wr!jUYunN%yADxr&*~vtPwOVw48Q~)~-FQ|5NWU zJmP{(^G#ov_L#1i{xx+mcQ?nGN0`+4l_kkC&B9yuT7I(BS?Vn>Edf@I zb%-_Jy2`rWdfED%Dkx`|od{aXHS#&~HS%xdN932~FXWvR1&b7s%KpkfmCIDyRVP$h zb%A<=dY$H?=8>j}HcER<>!<6k8>XA1Tcf+Bd!*CqkM&*EW=L2A;SZM zyD`$3Xq;pG+E{ID&W+`ka%Z_0TnCfUlwz8JivMhSW(qgQm?xSKm|vLvEP6|tWtL@u z<*22)!1Bi8X>D#DXDzaBvHoa%Otp>1_nD%$W93`r$K?;?O%>f0gA{p+wTf>Q)e2VG zS=m=PNx59PUwKveO4(l3OO>TsqS~ptsQOdouU4zg>QU->>P70E>eK3r>KE#knzou~ z%?M4FW{GB-X1C^&re5>6roGmvE$F4q))s5aw0pJZv{$vSwEnsfU94`D?gQO+-D#bl zK2e{iU#BwOCaqa#`OfmxVzLglrdj7%4_N=PG6_rpGZbeUB2Sc0m9LlA z$~_bZ6!#RK$|&VfMK>b%B22I9i*9~d8PRX6@H`*HiQ^w zaBalw>5%CMQ@zOp{|vaLIm{eo{s;wEnSV6bm|I%TSzcS3 zS;Nr5Vy*qHW31z?)2&t3YU?BGODmI$Sv(HvE$<*tlWP^@6~`5~6*Y?2iZ;r2%I?ZE z^#A2bqTH-JtYlO^s;(-vs;WSBR&`0$R^3glP>)mRs^_W~t5>KusV}JuG#fPAHHS1O zG}krHHK3Jg1GJsAL$qnyN!mQ^Z0#29SK4yz73~czqw~{s&~?KNoTy9DrRhfN#_J~Q zrt9YFigh;K$GWw;O}Lolx`Vpox}S7E>#phU=^pD|>7@D~eL=XMLvxJN=jx~H=jiw7 zZ|fiF>-GMI?+sTCw+s&rZwwuccks91Od-PzMj*vK?x9Rq)+>9d#;H$ghw6XP-^GpE z+c3cpWKLHT#`O1Yn6xMHMYj3QexL2*KLRdrJ(QMXg;)EVlD>S<`7t?C2n zqv|W_YV{MfmnKkCq}ihRP2-{U*5+$x>PmH4hAD={#y!TLjK3NGHL{!p)sS<&xdhyp z>p463Eq9*-lgt!k>Sih!U>ae{G>tW_H*H2gy<@5|)tUm#?adv{qs-&X6U;oW{$}$w z^AF}L<{Rc}v%5uRX>AF#^t8lV23b-pi!2{m)>*!=d~Z2#xnYr7r&#CGkh2MIXE?Fu za({U<#Yc(_+Ap-bweh+fwDEeh@4^HZC=~acfY!P25&)JGYZ7 z=k{?-Im4(?$W8T2^(!@_ao0#RQjJXGtMS(aX@WIjn(3Oa3?~dJC~BQC1~(ltS7O$V zpqc!TLakKljJlb+LfsSH3thebrM{a%i9yR?G#h&wV~l-`@y3Eg;}B!2G0m87G;=+< z7_KiD&n0q0xKu8U%cKG?;QbSUuR32n8>8bo^+sF()~GXCP18+tP5WuUs&?|26ulK6 zDi$be)Q@$~bP;-`ekj+%9AHi`r~@t9y9$!jd()~?p>Rt4@NLxI(7?P-m%_C+xu zYQ8|bLHn6@oAyiX*BF!zXurYZ>6rGU_PIXPI0)5D;zpY6re@|)T$~r?6iat&A8Rsh z#a!zg>k{ia>u&2wYb{j@^U9S77`dOkqg)}k%KOPj%JbxZ%AYAJl?rWt+$pnk1)t)! zsM7t8n;}78Y*=TwXaJ+k*vV)zCK-p}nK#Qg&$z_+k#UpJn`^;!+uBoY|DaO>#lxtpW-fzBOZej7W1Y5!_atmj9-?GWl+nQn>Yh8p85I`@>2z=I;*;?I8|>| zU)6ZkB-KjQY1Qv4FSSA4S)0nV>23V@Cj2y(M+e*<_Q7~4yKzUjDT2-!Lv)yAJ7KtDxMT1&h8wNMIP{tf+~*$~zrc-l$#~m%Q9QVSh6!f9@`myrP5@LA zRWK?aqZ)=s&t_EekS1L_UOP=Y3s0Q2xTuZ-Z4X^PT?r0(PUo)gte>x6p}(x(i32$d zU5&NIKaK4$e6%ukHuW~GGTkhLmC2@r&v=RdaQKIt63Nx9Wn{n*EyZHOsUwbshEZ z=`%6*DUC+sbmKzfr^e5XXN~ub&x{P`g8}3{+!=$o6mBv`vrllNe$G{LKX4DYr+C)? z%lVmtO(s(x(*RSVX#(zykMS(|4AYhqrt_vc(+f;p7;}hOVU9NsHK$>0S%nk1Y_2Xa z-#0%pODqu7+*vgE=R~0zR zvGNl668Rj(ZbiIuwDNo9KT3C12bEbJqdu<|)U7c_bk=AzCe3@AG|d>zM9o9Z3ynk@ zsMTr*Ytyxp@f0c57JR3z(*B^msIAlfqjlG{(6!Y?=!$gT>aOSnLu;ef$QfgCA7o*6 zv(tFgc;0voqk3;{HdluEO_FIg&QE6^W-c^;X5M2yXg+2>Yrbf{ic9nx?t>UhuH|FP zAwN1m>v`)<=N8R{0`X8`yGk)Ql|CLHPiLh_17gBSDHUTMR%ABaXbD^{bhN9b3Znd$H-IUlj;L?38t)<)c4d5brX#o6W4)g;0>D3(Zo+Q ze`!K+8(Op(+D~yK{-V9FZG$;vHXg}GbpO#w^nToMPG_nxO)@XD#1vR(;$eZWs8E?I zMYQU?>aOOo#-Z`jcGfC!lkCt+bz!=}n1Ftb>DUvULSK%l*du*AjO4uxXKOShh>SFbFwOw7Q{#hNUQE4hPXEm2Kw{ez5c%uEO zZKCUlzH(ak2c{FHhR-o;IBTdgcpL8;yK)N7fG0{{ye&-TE^@bUpSVcRYtWlS%pQ}OBOcS7q)Ffa`?4|9i9fe6bKc=4_ zsy(ok)9Wx(%Iul^q>(LaO$ delta 19603 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 0 && edgeStrength <= 5, "EdgeStrength must be between 0 and 5") - Assert(sharpness >= 0 && sharpness <= 1.5, "Sharpness must be between 0 and 1.5") - Assert(convert || thirdPass, "ThirdPass is required when Convert=false") + EdgeStrength = default(EdgeStrength, 1) + Sharpness = default(Sharpness, 1) + ThirdPass = default(ThirdPass, true) + PrecisionIn = default(PrecisionIn, 0) + convert = PrecisionIn==0 + + Assert(EdgeStrength >= 0 && EdgeStrength <= 5, "EdgeStrength must be between 0 and 5") + Assert(Sharpness >= 0 && Sharpness <= 1.5, "Sharpness must be between 0 and 1.5") + Assert(convert || ThirdPass, "ThirdPass is required when PrecisionIn > 0") + Assert(PrecisionIn >= 0 && PrecisionIn <= 3, "PrecisionIn must be between 0 and 3") - input + Input - convertYuv = convert && !IsRGB() + #convertYuv = convert && !IsRGB() sourceFormat = IsYV12() ? "YV12" : IsYV24() ? "YV24" : IsRGB24() ? "RGB24" : "RGB32" - input = convert ? ConvertToFloat(precision=1) : last + Input = convert ? ConvertToShader(Precision=2) : last - input - inputWidth = convert ? width : width / 2 - inputHeight = height - args_string = string(edgeStrength,"%.32f") + "," + string(sharpness,"%.32f") + "0,0f" - size0_string = string(inputWidth) + "," + string(inputHeight)+"," + string(1./InputWidth,"%.32f") + "," + string(1./height,"%.32f")+"f" - size1_string = string(2*inputWidth) + "," + string(2*inputHeight) + "," + string(1./(2*inputWidth),"%.32f") + "," + string(1./(2*inputHeight),"%.32f")+"f" + Input + InputWidth = Width / (PrecisionIn==0 || PrecisionIn==1 ? 2 : 2) + InputHeight = Height + args_string = string(EdgeStrength,"%.32f") + "," + string(Sharpness,"%.32f") + ",0,0f" + size0_string = string(InputWidth) + "," + string(InputHeight) + "," + string(1./InputWidth,"%.32f") + "," + string(1./InputHeight,"%.32f") + "f" + size1_string = string(2*InputWidth) + "," + string(2*InputHeight) + "," + string(1./(2*InputWidth),"%.32f") + "," + string(1./(2*InputHeight),"%.32f") + "f" # It works just as well in YUV colorspace #convertYuv ? Shader("YuvToGamma.cso") : nop Shader("super-xbr-pass0.cso",\ - param2=args_string,\ - param3=size0_string,\ - width=2*inputWidth,height=2*inputHeight) + Param2 = args_string,\ + Param3 = size0_string,\ + Width = 2*InputWidth, Height = 2*InputHeight) Shader("super-xbr-pass1.cso",\ - param2=args_string,\ - param3=size1_string) + Param2=args_string,\ + Param3=size1_string) - thirdPass ? Shader("super-xbr-pass2.cso",\ - param2=args_string,\ - param3=size1_string) : nop + ThirdPass ? Shader("super-xbr-pass2.cso",\ + Param2=args_string,\ + Param3=size1_string) : nop #convertYuv ? Shader("GammaToYuv.cso") : nop - last.ExecuteShader(input, precision=2, precisionIn=convert?1:2, precisionOut=convert?1:2) + last.ExecuteShader(Input, Precision=2, PrecisionIn=convert?1:PrecisionIn, PrecisionOut=convert?1:PrecisionIn) - convert ? ConvertFromFloat(format=sourceFormat, precision=1) : last + convert ? ConvertFromShader(Format=sourceFormat, Precision=1) : last - !thirdPass ? spline36resize(width, height, -.5, -.5, width, height) : last + !ThirdPass ? spline36resize(2*InputWidth, 2*InputHeight, -.5, -.5, 2*InputWidth, 2*InputHeight) : last } \ No newline at end of file diff --git a/Shaders/SuperRes/SuperRes.avsi b/Shaders/SuperRes/SuperRes.avsi index 8172790..d69e15d 100644 --- a/Shaders/SuperRes/SuperRes.avsi +++ b/Shaders/SuperRes/SuperRes.avsi @@ -1,48 +1,53 @@ -function SuperRes(clip input, int "passes", float "strength", float "softness", string "upscalecommand", bool "srcMatrix601", bool "convert") +function SuperRes(clip Input, int "Passes", float "Strength", float "Softness", string "UpscaleCommand", bool "SrcMatrix601", int "PrecisionIn") { - passes = default(passes, 1) - strength = default(strength, 1) - softness = default(softness, 0) - convert = default(convert, true) - srcMatrix601 = default(srcMatrix601, false) - - Assert((passes > 0 && passes <= 3) ? true : false, "Passes must be between 1 and 3") - Assert((strength >= 0 && strength <= 1) ? true : false, "Strength must be between 0 and 1") - Assert((softness >= 0 && softness <= 1) ? true : false, "Softness must be between 0 and 1") - Assert(Defined(upscalecommand), "You must specify upscalecommand") - - input - - convertYuv = convert && !IsRGB() + Passes = default(Passes, 1) + Strength = default(Strength, 1) + Softness = default(Softness, 0) + SrcMatrix601 = default(SrcMatrix601, false) + PrecisionIn = default(PrecisionIn, 0) + convert = PrecisionIn==0 + + Assert((Passes > 0 && Passes <= 3) ? true : false, "Passes must be between 1 and 3") + Assert((Strength >= 0 && Strength <= 1) ? true : false, "Strength must be between 0 and 1") + Assert((Softness >= 0 && Softness <= 1) ? true : false, "Softness must be between 0 and 1") + Assert(Defined(UpscaleCommand), "You must specify UpscaleCommand") + Assert(PrecisionIn >= 0 && PrecisionIn <= 3, "PrecisionIn must be between 0 and 3") + + Input + + ConvertYuv = convert && !IsRGB() sourceFormat = IsYV12 ? "YV12" : IsYV24 ? "YV24" : IsRGB24 ? "RGB24" : IsRGB32 ? "RGB32" : "" Assert(sourceFormat != "", chr(10) + "Source must be YV12, YV24, RGB24 or RGB32" + chr(10)) - original = convert ? ConvertToFloat(precision=1) : last - Eval(upscalecommand) - input = convert ? ConvertToFloat(precision=1) : last - input.Shader(convertYuv && srcMatrix601 ? "Yuv601ToLinear.cso" : convertYuv ? "YuvToLinear.cso" : "GammaToLinear.cso") - SuperResPass(last, input, original, strength, softness, 1, passes, convertYuv, srcMatrix601) - passes > 1 ? SuperResPass(input, original, strength, softness, 2, passes, convertYuv, srcMatrix601) : nop - passes > 2 ? SuperResPass(input, original, strength, softness, 3, passes, convertYuv, srcMatrix601) : nop - !convert && srcMatrix601 ? Shader("Yuv601ToGamma.cso").Shader("GammaToYuv.cso") : last - - ExecuteShader(last, input, original, precision=3, precisionIn=convert?1:2, precisionOut=convert?1:2) - convert ? ConvertFromFloat(format=sourceFormat, precision=1) : last + Original = convert ? ConvertToShader(precision=1) : last + Eval(UpscaleCommand) + Input = convert ? ConvertToShader(precision=1) : last + Input.Shader(ConvertYuv && SrcMatrix601 ? "Yuv601ToLinear.cso" : ConvertYuv ? "YuvToLinear.cso" : "GammaToLinear.cso") + SuperResPass(last, Input, Original, Strength, Softness, 1, Passes, ConvertYuv, SrcMatrix601, PrecisionIn) + Passes > 1 ? SuperResPass(Input, Original, Strength, Softness, 2, Passes, ConvertYuv, SrcMatrix601, PrecisionIn) : nop + Passes > 2 ? SuperResPass(Input, Original, Strength, Softness, 3, Passes, ConvertYuv, SrcMatrix601, PrecisionIn) : nop + !convert && SrcMatrix601 ? Shader("Yuv601ToGamma.cso").Shader("GammaToYuv.cso") : last + + ExecuteShader(last, Input, Original, precision=3, PrecisionIn=convert?1:PrecisionIn, precisionOut=convert?1:PrecisionIn) + convert ? ConvertFromShader(format=sourceFormat, precision=1) : last } -function SuperResPass(clip cmd, clip input, clip original, float strength, float softness, int pass, int passes, bool convertYuv, bool srcMatrix601) +function SuperResPass(clip cmd, clip Input, clip Original, float Strength, float Softness, int Pass, int Passes, bool ConvertYuv, bool SrcMatrix601, int PrecisionIn) { - cmd.Shader("Bicubic.cso", output=3, \ - param0=string(original.Width) + "," + string(original.Height) + "," + string(1./original.Width,"%.32f") + "," + string(1./original.Height,"%.32f") + "f",\ - param1=string(input.Width) + "," + string(input.Height) + "," + string(1./input.Width,"%.32f") + "," + string(1./input.Height,"%.32f") + "f",\ - param2=string(1/3.,"%.32f") + "," + string(1/3.,"%.32f") + "f",\ - width=original.Width, height=original.Height) - - Shader(convertYuv && srcMatrix601 ? "SuperResDiff601.cso" : convertYuv ? "SuperResDiff709.cso" : "SuperResDiff.cso", clip1=3, clip2=2, output=4) - - Shader(pass==passes ? (convertYuv ? "SuperResFinal709.cso" : "SuperResFinal.cso") : "SuperRes.cso", clip1=1, clip2=4, output=1, \ - param0=string(input.Width) + "," + string(input.Height) + "f", \ - param1=string(1./input.Width, "%.32f") + "," + string(1./input.Height, "%.32f") + "f", \ - param2=string(original.Width) + "," + string(original.Height) + "," + string(1./(original.Width),"%.32f") + "," + string(1./original.Height,"%.32f") + "f", \ - Param3=string(strength,"%.32f") + "," + string(softness,"%.32f") + "," + string(pass) + "," + string(passes) + "f") + InputWidth = Input.Width / ((PrecisionIn==0 || PrecisionIn==1) ? 1 : 2) + OriginalWidth = Original.Width / ((PrecisionIn==0 || PrecisionIn==1) ? 1 : 2) + + cmd.Shader("Bicubic.cso", Output=3, \ + Param0=string(OriginalWidth) + "," + string(Original.Height) + "," + string(1./OriginalWidth,"%.32f") + "," + string(1./Original.Height,"%.32f") + "f",\ + Param1=string(InputWidth) + "," + string(Input.Height) + "," + string(1./InputWidth,"%.32f") + "," + string(1./Input.Height,"%.32f") + "f",\ + Param2=string(1/3.,"%.32f") + "," + string(1/3.,"%.32f") + "f",\ + Width=OriginalWidth, Height=Original.Height) + + Shader(ConvertYuv && SrcMatrix601 ? "SuperResDiff601.cso" : ConvertYuv ? "SuperResDiff709.cso" : "SuperResDiff.cso", Clip1=3, Clip2=2, Output=4) + + Shader(Pass==Passes ? (ConvertYuv ? "SuperResFinal709.cso" : "SuperResFinal.cso") : "SuperRes.cso", Clip1=1, Clip2=4, Output=1, \ + Param0=string(InputWidth) + "," + string(Input.Height) + "f", \ + Param1=string(1./InputWidth, "%.32f") + "," + string(1./Input.Height, "%.32f") + "f", \ + Param2=string(OriginalWidth) + "," + string(Original.Height) + "," + string(1./(OriginalWidth),"%.32f") + "," + string(1./Original.Height,"%.32f") + "f", \ + Param3=string(Strength,"%.32f") + "," + string(Softness,"%.32f") + "," + string(Pass) + "," + string(Passes) + "f") } \ No newline at end of file diff --git a/Src/AviSynthShader.vcxproj b/Src/AviSynthShader.vcxproj index f7cdc18..09817d8 100644 --- a/Src/AviSynthShader.vcxproj +++ b/Src/AviSynthShader.vcxproj @@ -102,16 +102,16 @@ - - + + - - + + diff --git a/Src/AviSynthShader.vcxproj.filters b/Src/AviSynthShader.vcxproj.filters index fd7ffba..049e90f 100644 --- a/Src/AviSynthShader.vcxproj.filters +++ b/Src/AviSynthShader.vcxproj.filters @@ -3,19 +3,19 @@ - - + + - - + + \ No newline at end of file diff --git a/Src/ConvertFromFloat.cpp b/Src/ConvertFromShader.cpp similarity index 82% rename from Src/ConvertFromFloat.cpp rename to Src/ConvertFromShader.cpp index 06ac196..44fe751 100644 --- a/Src/ConvertFromFloat.cpp +++ b/Src/ConvertFromShader.cpp @@ -1,13 +1,13 @@ -#include "ConvertFromFloat.h" +#include "ConvertFromShader.h" -ConvertFromFloat::ConvertFromFloat(PClip _child, const char* _format, bool _convertYuv, int _precision, IScriptEnvironment* env) : - GenericVideoFilter(_child), precision(_precision), format(_format), convertYUV(_convertYuv) { +ConvertFromShader::ConvertFromShader(PClip _child, const char* _format, int _precision, IScriptEnvironment* env) : + GenericVideoFilter(_child), precision(_precision), format(_format) { if (!vi.IsRGB32()) - env->ThrowError("ConvertFromFloat: Source must be float-precision RGB"); + env->ThrowError("ConvertFromShader: Source must be float-precision RGB"); if (strcmp(format, "YV12") != 0 && strcmp(format, "YV24") != 0 && strcmp(format, "RGB24") != 0 && strcmp(format, "RGB32") != 0) - env->ThrowError("ConvertFromFloat: Destination format must be YV12, YV24, RGB24 or RGB32"); + env->ThrowError("ConvertFromShader: Destination format must be YV12, YV24, RGB24 or RGB32"); if (precision < 1 || precision > 3) - env->ThrowError("ConvertFromFloat: Precision must be 1, 2 or 3"); + env->ThrowError("ConvertFromShader: Precision must be 1, 2 or 3"); viDst = vi; if (strcmp(format, "RGB32") == 0) @@ -35,7 +35,7 @@ ConvertFromFloat::ConvertFromFloat(PClip _child, const char* _format, bool _conv } } -ConvertFromFloat::~ConvertFromFloat() { +ConvertFromShader::~ConvertFromShader() { if (precision == 3) { free(floatBuffer); free(halfFloatBuffer); @@ -43,7 +43,7 @@ ConvertFromFloat::~ConvertFromFloat() { } -PVideoFrame __stdcall ConvertFromFloat::GetFrame(int n, IScriptEnvironment* env) { +PVideoFrame __stdcall ConvertFromShader::GetFrame(int n, IScriptEnvironment* env) { PVideoFrame src = child->GetFrame(n, env); // Convert from float-precision RGB to YV24 @@ -57,7 +57,7 @@ PVideoFrame __stdcall ConvertFromFloat::GetFrame(int n, IScriptEnvironment* env) return dst; } -void ConvertFromFloat::convFloatToYV24(const byte *src, unsigned char *py, unsigned char *pu, unsigned char *pv, +void ConvertFromShader::convFloatToYV24(const byte *src, unsigned char *py, unsigned char *pu, unsigned char *pv, int pitch1, int pitch2Y, int pitch2UV, int width, int height, IScriptEnvironment* env) { const byte* srcLoop = precision == 3 ? floatBuffer : src; @@ -87,7 +87,7 @@ void ConvertFromFloat::convFloatToYV24(const byte *src, unsigned char *py, unsig } } -void ConvertFromFloat::convFloatToRGB32(const byte *src, unsigned char *dst, +void ConvertFromShader::convFloatToRGB32(const byte *src, unsigned char *dst, int pitchSrc, int pitchDst, int width, int height, IScriptEnvironment* env) { const byte* srcLoop = precision == 3 ? floatBuffer : src; @@ -119,8 +119,8 @@ void ConvertFromFloat::convFloatToRGB32(const byte *src, unsigned char *dst, } // Using Rec601 color space. Can be optimized with MMX assembly or by converting on the GPU with a shader. -// For ConvertToFloat, it's faster to process in INT, but for ConvertFromFloat, processing with FLOAT is faster -void ConvertFromFloat::convFloat(const byte* src, unsigned char* outY, unsigned char* outU, unsigned char* outV) { +// For ConvertToShader, it's faster to process in INT, but for ConvertFromShader, processing with FLOAT is faster +void ConvertFromShader::convFloat(const byte* src, unsigned char* outY, unsigned char* outU, unsigned char* outV) { float r, g, b; float y2, u2, v2; short y, u, v; @@ -184,7 +184,7 @@ void ConvertFromFloat::convFloat(const byte* src, unsigned char* outY, unsigned } // Shortcut to process BYTE or UINT16 values faster when not converting colors -void ConvertFromFloat::convInt(const byte* src, unsigned char* outY, unsigned char* outU, unsigned char* outV) { +void ConvertFromShader::convInt(const byte* src, unsigned char* outY, unsigned char* outU, unsigned char* outV) { if (precision == 1) { outV[0] = src[0]; outU[0] = src[1]; @@ -205,7 +205,7 @@ void ConvertFromFloat::convInt(const byte* src, unsigned char* outY, unsigned ch } } -uint16_t ConvertFromFloat::sadd16(uint16_t a, uint16_t b) +uint16_t ConvertFromShader::sadd16(uint16_t a, uint16_t b) { return (a > 0xFFFF - b) ? 0xFFFF : a + b; } \ No newline at end of file diff --git a/Src/ConvertFromFloat.h b/Src/ConvertFromShader.h similarity index 84% rename from Src/ConvertFromFloat.h rename to Src/ConvertFromShader.h index 6b30ae2..513ceec 100644 --- a/Src/ConvertFromFloat.h +++ b/Src/ConvertFromShader.h @@ -7,16 +7,16 @@ #include "d3dx9.h" // Converts float-precision RGB data (12-byte per pixel) into YV12 format. -class ConvertFromFloat : public GenericVideoFilter { +class ConvertFromShader : public GenericVideoFilter { public: - ConvertFromFloat(PClip _child, const char* _format, bool _convertYuv, int _precision, IScriptEnvironment* env); - ~ConvertFromFloat(); + ConvertFromShader(PClip _child, const char* _format, int _precision, IScriptEnvironment* env); + ~ConvertFromShader(); PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); const VideoInfo& __stdcall GetVideoInfo() { return viDst; } private: const int precision; int precisionShift; - const bool convertYUV; + const bool convertYUV = false; unsigned char* floatBuffer; int floatBufferPitch; unsigned char* halfFloatBuffer; diff --git a/Src/ConvertToFloat.cpp b/Src/ConvertToShader.cpp similarity index 85% rename from Src/ConvertToFloat.cpp rename to Src/ConvertToShader.cpp index fe2946a..0e7a2b0 100644 --- a/Src/ConvertToFloat.cpp +++ b/Src/ConvertToShader.cpp @@ -1,11 +1,11 @@ -#include "ConvertToFloat.h" +#include "ConvertToShader.h" -ConvertToFloat::ConvertToFloat(PClip _child, bool _convertYuv, int _precision, IScriptEnvironment* env) : - GenericVideoFilter(_child), precision(_precision), convertYUV(_convertYuv) { +ConvertToShader::ConvertToShader(PClip _child, int _precision, IScriptEnvironment* env) : + GenericVideoFilter(_child), precision(_precision) { if (!vi.IsYV24() && !vi.IsRGB24() && !vi.IsRGB32()) - env->ThrowError("ConvertToFloat: Source must be YV12, YV24, RGB24 or RGB32"); + env->ThrowError("ConvertToShader: Source must be YV12, YV24, RGB24 or RGB32"); if (precision < 1 && precision > 3) - env->ThrowError("ConvertToFloat: Precision must be 1, 2 or 3"); + env->ThrowError("ConvertToShader: Precision must be 1, 2 or 3"); viDst = vi; viDst.pixel_type = VideoInfo::CS_BGR32; @@ -27,14 +27,14 @@ ConvertToFloat::ConvertToFloat(PClip _child, bool _convertYuv, int _precision, I } } -ConvertToFloat::~ConvertToFloat() { +ConvertToShader::~ConvertToShader() { if (precision == 3) { free(floatBuffer); free(halfFloatBuffer); } } -PVideoFrame __stdcall ConvertToFloat::GetFrame(int n, IScriptEnvironment* env) { +PVideoFrame __stdcall ConvertToShader::GetFrame(int n, IScriptEnvironment* env) { PVideoFrame src = child->GetFrame(n, env); // Convert from YV24 to half-float RGB @@ -49,7 +49,7 @@ PVideoFrame __stdcall ConvertToFloat::GetFrame(int n, IScriptEnvironment* env) { return dst; } -void ConvertToFloat::convYV24ToFloat(const byte *py, const byte *pu, const byte *pv, +void ConvertToShader::convYV24ToFloat(const byte *py, const byte *pu, const byte *pv, unsigned char *dst, int pitch1Y, int pitch1UV, int pitch2, int width, int height, IScriptEnvironment* env) { unsigned char* dstLoop = precision == 3 ? floatBuffer : dst; @@ -84,7 +84,7 @@ void ConvertToFloat::convYV24ToFloat(const byte *py, const byte *pu, const byte } } -void ConvertToFloat::convRgbToFloat(const byte *src, unsigned char *dst, int srcPitch, int dstPitch, int width, int height, IScriptEnvironment* env) { +void ConvertToShader::convRgbToFloat(const byte *src, unsigned char *dst, int srcPitch, int dstPitch, int width, int height, IScriptEnvironment* env) { unsigned char* dstLoop = precision == 3 ? floatBuffer : dst; int dstLoopPitch = precision == 3 ? floatBufferPitch : dstPitch; @@ -118,7 +118,7 @@ void ConvertToFloat::convRgbToFloat(const byte *src, unsigned char *dst, int src } // Using Rec601 color space. Can be optimized with MMX assembly or by converting on the GPU with a shader. -void ConvertToFloat::convFloat(unsigned char y, unsigned char u, unsigned char v, unsigned char* out) { +void ConvertToShader::convFloat(unsigned char y, unsigned char u, unsigned char v, unsigned char* out) { int r, g, b; if (convertYUV) { b = 1164 * (y - 16) + 2018 * (u - 128); @@ -197,7 +197,7 @@ void ConvertToFloat::convFloat(unsigned char y, unsigned char u, unsigned char v } // Shortcut to process BYTE or UINT16 values faster when not converting colors -void ConvertToFloat::convInt(unsigned char y, unsigned char u, unsigned char v, unsigned char* out) { +void ConvertToShader::convInt(unsigned char y, unsigned char u, unsigned char v, unsigned char* out) { if (precision == 1) { out[0] = v; out[1] = u; @@ -212,7 +212,7 @@ void ConvertToFloat::convInt(unsigned char y, unsigned char u, unsigned char v, } // restrictions: src_stride MUST BE a multiple of 8, dst_stride MUST BE a multiple of 64 and 8x src_stride (x4 planes, x2 pixel size) -void ConvertToFloat::bitblt_i8_to_i16_sse2(const uint8_t* srcY, const uint8_t* srcU, const uint8_t* srcV, int srcPitch, uint16_t* dst, int dstPitch, int height) +void ConvertToShader::bitblt_i8_to_i16_sse2(const uint8_t* srcY, const uint8_t* srcU, const uint8_t* srcV, int srcPitch, uint16_t* dst, int dstPitch, int height) { assert(srcPitch % 2 == 0); assert(dstPitch % 16 == 0); @@ -250,7 +250,7 @@ void ConvertToFloat::bitblt_i8_to_i16_sse2(const uint8_t* srcY, const uint8_t* s } } -__m128i ConvertToFloat::load_8_16l(const void *lsb_ptr, __m128i zero) +__m128i ConvertToShader::load_8_16l(const void *lsb_ptr, __m128i zero) { assert(lsb_ptr != 0); @@ -262,7 +262,7 @@ __m128i ConvertToFloat::load_8_16l(const void *lsb_ptr, __m128i zero) return (val); } -void ConvertToFloat::store_8_16l(void *lsb_ptr, __m128i val, __m128i mask_lsb) +void ConvertToShader::store_8_16l(void *lsb_ptr, __m128i val, __m128i mask_lsb) { assert(lsb_ptr != 0); diff --git a/Src/ConvertToFloat.h b/Src/ConvertToShader.h similarity index 79% rename from Src/ConvertToFloat.h rename to Src/ConvertToShader.h index f7a8617..888525d 100644 --- a/Src/ConvertToFloat.h +++ b/Src/ConvertToShader.h @@ -7,16 +7,16 @@ #include "d3dx9.h" // Converts YV12 data into RGB data with float precision, 12-byte per pixel. -class ConvertToFloat : public GenericVideoFilter { +class ConvertToShader : public GenericVideoFilter { public: - ConvertToFloat(PClip _child, bool _convertYuv, int _precision, IScriptEnvironment* env); - ~ConvertToFloat(); + ConvertToShader(PClip _child, int _precision, IScriptEnvironment* env); + ~ConvertToShader(); PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); const VideoInfo& __stdcall GetVideoInfo() { return viDst; } private: const int precision; int precisionShift; - const bool convertYUV; + const bool convertYUV = false; const float AlphaFloat = 1; const unsigned short AlphaShort = 0; // UINT16_MAX; unsigned char* floatBuffer; @@ -28,7 +28,7 @@ class ConvertToFloat : public GenericVideoFilter { void convRgbToFloat(const byte *src, unsigned char *dst, int srcPitch, int dstPitch, int width, int height, IScriptEnvironment* env); void convFloat(unsigned char y, unsigned char u, unsigned char v, unsigned char *out); void convInt(byte y, unsigned char u, unsigned char v, unsigned char* out); - void ConvertToFloat::bitblt_i8_to_i16_sse2(const uint8_t* srcY, const uint8_t* srcU, const uint8_t* srcV, int srcPitch, uint16_t* dst, int dstPitch, int height); + void ConvertToShader::bitblt_i8_to_i16_sse2(const uint8_t* srcY, const uint8_t* srcU, const uint8_t* srcV, int srcPitch, uint16_t* dst, int dstPitch, int height); __m128i load_8_16l(const void *lsb_ptr, __m128i zero); void store_8_16l(void *lsb_ptr, __m128i val, __m128i mask_lsb); VideoInfo viDst; diff --git a/Src/ExecuteShader.cpp b/Src/ExecuteShader.cpp index a50b7b5..f180b66 100644 --- a/Src/ExecuteShader.cpp +++ b/Src/ExecuteShader.cpp @@ -149,7 +149,7 @@ void ExecuteShader::CreateInputClip(int index, IScriptEnvironment* env) { PClip clip = m_clips[index]; if (clip != NULL) { if (!clip->GetVideoInfo().IsRGB32()) - env->ThrowError("ExecuteShader: Source must be float-precision RGB"); + env->ThrowError("ExecuteShader: You must first call ConvertToShader on source"); if (FAILED(render->CreateInputTexture(index, index + 1, clip->GetVideoInfo().width / precisionIn, clip->GetVideoInfo().height, true, false))) env->ThrowError("ExecuteShader: Failed to create input textures."); diff --git a/Src/Init.cpp b/Src/Init.cpp index 4139c53..9756d2f 100644 --- a/Src/Init.cpp +++ b/Src/Init.cpp @@ -1,41 +1,28 @@ #include #include "avisynth.h" -#include "ConvertToFloat.h" -#include "ConvertFromFloat.h" +#include "ConvertToShader.h" +#include "ConvertFromShader.h" #include "Shader.h" #include "ExecuteShader.h" -const int DefaultPrecision = 2; const int DefaultConvertYuv = false; -AVSValue __cdecl Create_ConvertToFloat(AVSValue args, void* user_data, IScriptEnvironment* env) { +AVSValue __cdecl Create_ConvertToShader(AVSValue args, void* user_data, IScriptEnvironment* env) { PClip input = args[0].AsClip(); - bool ConvertYuv = args[1].AsBool(DefaultConvertYuv); if (input->GetVideoInfo().IsYV12()) input = env->Invoke("ConvertToYV24", input).AsClip(); - // Don't convert YUV to RGB when source format is RGB32. - if (input->GetVideoInfo().IsRGB32()) - ConvertYuv = false; - return new ConvertToFloat( + return new ConvertToShader( input, // source clip - ConvertYuv, // whether to convert YUV to RGB on the CPU - args[2].AsInt(DefaultPrecision), // precision, 1 for RGB32, 2 for UINT16 and 3 for half-float data. + args[1].AsInt(1), // precision, 1 for RGB32, 2 for UINT16 and 3 for half-float data. env); // env is the link to essential informations, always provide it } -AVSValue __cdecl Create_ConvertFromFloat(AVSValue args, void* user_data, IScriptEnvironment* env) { - const char* Format = args[1].AsString("YV12"); - bool ConvertYuv = args[2].AsBool(DefaultConvertYuv); - // Don't convert RGB to YUV when destination format is RGB32. - if (strcmp(Format, "RGB32") == 0) - ConvertYuv = false; - - ConvertFromFloat* Result = new ConvertFromFloat( +AVSValue __cdecl Create_ConvertFromShader(AVSValue args, void* user_data, IScriptEnvironment* env) { + ConvertFromShader* Result = new ConvertFromShader( args[0].AsClip(), // source clip - Format, // destination format - ConvertYuv, // whether to convert RGB to YUV on the CPU - args[3].AsInt(DefaultPrecision), // precision, 1 for RGB32, 2 for UINT16 and 3 for half-float data. + args[1].AsString("YV12"), // destination format + args[2].AsInt(1), // precision, 1 for RGB32, 2 for UINT16 and 3 for half-float data. env); // env is the link to essential informations, always provide it if (strcmp(args[1].AsString("YV12"), "YV12") == 0) @@ -75,8 +62,6 @@ AVSValue __cdecl Create_Shader(AVSValue args, void* user_data, IScriptEnvironmen } AVSValue __cdecl Create_ExecuteShader(AVSValue args, void* user_data, IScriptEnvironment* env) { - int Precision = args[10].AsInt(DefaultPrecision); // precision - return new ExecuteShader( args[0].AsClip(), // source clip containing commands args[1].AsClip(), // clip 1 @@ -88,9 +73,9 @@ AVSValue __cdecl Create_ExecuteShader(AVSValue args, void* user_data, IScriptEnv args[7].AsClip(), // clip 7 args[8].AsClip(), // clip 8 args[9].AsClip(), // clip 9 - Precision, // precision - args[11].AsInt(Precision), // precisionIn - args[12].AsInt(Precision), // precisionOut + args[10].AsInt(2), // precision + args[11].AsInt(1), // precisionIn + args[12].AsInt(1), // precisionOut env); } @@ -98,9 +83,9 @@ const AVS_Linkage *AVS_linkage = 0; extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) { AVS_linkage = vectors; - env->AddFunction("ConvertToFloat", "c[convertYuv]b[precision]i", Create_ConvertToFloat, 0); - env->AddFunction("ConvertFromFloat", "c[format]s[convertYuv]b[precision]i", Create_ConvertFromFloat, 0); - env->AddFunction("Shader", "c[path]s[entryPoint]s[shaderModel]s[param0]s[param1]s[param2]s[param3]s[param4]s[param5]s[param6]s[param7]s[param8]s[clip1]i[clip2]i[clip3]i[clip4]i[clip5]i[clip6]i[clip7]i[clip8]i[clip9]i[output]i[width]i[height]i", Create_Shader, 0); - env->AddFunction("ExecuteShader", "c[clip1]c[clip2]c[clip3]c[clip4]c[clip5]c[clip6]c[clip7]c[clip8]c[clip9]c[precision]i[precisionIn]i[precisionOut]i", Create_ExecuteShader, 0); + env->AddFunction("ConvertToShader", "c[Precision]i", Create_ConvertToShader, 0); + env->AddFunction("ConvertFromShader", "c[Format]s[Precision]i", Create_ConvertFromShader, 0); + env->AddFunction("Shader", "c[Path]s[EntryPoint]s[ShaderModel]s[Param0]s[Param1]s[Param2]s[Param3]s[Param4]s[Param5]s[Param6]s[Param7]s[Param8]s[Clip1]i[Clip2]i[Clip3]i[Clip4]i[Clip5]i[Clip6]i[Clip7]i[Clip8]i[Clip9]i[Output]i[Width]i[Height]i", Create_Shader, 0); + env->AddFunction("ExecuteShader", "c[Clip1]c[Clip2]c[Clip3]c[Clip4]c[Clip5]c[Clip6]c[Clip7]c[Clip8]c[Clip9]c[Precision]i[PrecisionIn]i[PrecisionOut]i", Create_ExecuteShader, 0); return "Shader plugin"; }