Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Hardware & Software > Software players

Reply
 
Thread Tools Search this Thread Display Modes
Old 4th June 2014, 16:13   #1  |  Link
Shiandow
Registered User
 
Join Date: Dec 2013
Posts: 753
Shader implementation of the NEDI algorithm

This post was written after I succeeded in implementing the NEDI algorithm (the one by Xin Li et al. not the nnedi3 algorithm by tritical) using shaders. I've since tried to write upscaling algorithms using variations on NEDI and other methods. The results of which can be found below.

NEDI:
For a short explanation of the NEDI algorithm see: http://chiranjivi.tripod.com/EDITut.html

NEDI's picture quality tends to be better than that of linear scaling algorithms (like Lanczos, Jinc, etc.) and in some cases beats nnedi3. It's especially good at scaling the image without aliasing. Development of this method has more or less finished, or otherwise superseded by SuperRes which uses NEDI as part of it's process.

Here is a quick comparison (these results are no longer up to date):
Nearest
Jinc3
nnedi3 (32 neurons)
NEDI

The easiest way to try NEDI is to use MPDN's render script capabilities. For details on how to use renderscripts see here.

To use the NEDI shaders for 2x upscaling with MadVR you should set MadVR to output YCbCr, by adding an empty file called "YCbCr" in the MadVR folder (or use the RGBtoYCbCr shader), and set MadVR to use a Nearest filter for luma upscaling (using NNEDI3 will also work but is obviously slower, using any other algorithm will give incorrect results). Also make sure that you're resizing the video exactly 2x, if this doesn't fit your screen you can usually force the video player to scale 2x anyway. You should then use the NEDI-I and NEDI-II shaders (in that order) post resize, and then you need to convert the result back to RGB. For Rec. 709 media this can be done by using the YCbCrtoRGB shader, unfortunately it probably won't work for all video types.

ChromaNEDI:
ChromaNEDI is a way of using NEDI to upscale chroma using information from the luma channels.

This project has largely been abandoned after I found out that this method causes a lot of chroma bleeding. I have been able to solve this, partially, by performing the scaling in linear light but this makes the NEDI artefacts (too) visible.

Anway, the chromaNEDI shaders can be used for chroma upscaling, currently this only works for 4:2:0 subsampled video but that seems to be 99.9% of all video. The way to use these shaders with MadVR is similar to how you use the NEDI shaders but should be used pre resize instead of post resize and you should set chroma upscaling to Nearest instead of luma upscaling. It consists of three different shaders (chromaNEDI-I up to chromaNEDI-III), which must all be used in order. The first two shaders work similarly to the two passes of the NEDI algorithm, the third one is necessary to align the chroma channels with the luma channel.

The chromaNEDI shaders also have support for several different chroma patterns, you can switch between these by changing the line "#define pattern x" where x should be 1,2,3 depending on which pattern you want. Make sure that you pick the same pattern for all shaders.

Short explanation:
pattern 1: this is most common for modern codecs.
pattern 2: used by mpeg-2, seems to be common for older codecs.
pattern 3: not used much but is useful for chroma-doubling (shaders should be used post-resize in that case and luma upscaling should be put to nearest. Only works for 2x resizing). You can skip the third shader when using this pattern.

SuperRes:
The SuperRes shaders use a different scaling method which can be used in combination with NEDI (or any other scaling algorithm). This method is explained in detail here. This method seems to give better results than just using NEDI, and rival those of NNEDI3. These are now also available as an MPDN renderscript.

SuperChromaRes:
With techniques similar to those of SuperRes it's also possible to do chroma scaling. One major advantage is that this makes it possible to do chroma scaling in linear light, which would normally be impossible. This can improve image quality greatly for images consisting of saturated colours (especially red) on a white background. This is also available as an MPDN renderscript, but I've also decided to make the original experimental shaders available to make it possible to try it out with other renderers. Be warned that support for these experimental shaders will be minimal, I will not be backporting all the improvements made in the renderscript, nor will I explain all the options, they also have some of the same issues as ChromaNEDI but will generally work well for HD sources.

Downloads:
More information on using MPDN and renderscripts:
http://forum.doom9.org/showthread.php?t=171120

Code of the NEDI shaders:
NEDI-I:
Code:
sampler s0 : register(s0);
float4 p0 :  register(c0);

#define width  (p0[0])
#define height (p0[1])

#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))

#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))

#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))

//Conjugate residual 
float2 solve(float2x2 A,float2 b) {
	float2 x = 1/4.0;
	float2 r = b - mul(A,x);
	float2 p = r;
	float2 Ar = mul(A,r);
	float2 Ap = Ar;
	for (int k = 0;k < 2; k++){
		float a = min(100,dot(r,Ar)/dot(Ap,Ap));
		x = x + a*p;
		float2 rk = r; float2 Ark = Ar;
		r = r - a*Ap;
		Ar = mul(A,r);
		float b = dot(r,Ar)/dot(rk,Ark);
		p = r + b*p;
		Ap = Ar + b*Ap;
	}
	return x;
}

//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }

float4 main(float2 tex : TEXCOORD0) : COLOR {
	float4 c0 = tex2D(s0,tex);

	//Skip pixels on wrong grid
 	if ((frac(tex.x*width/2.0)<0.5)||(frac(tex.y*height/2.0)<0.5)) return c0;
	
	//Define window and directions
	float2 dir[4] = {{-1,-1},{1,1},{-1,1},{1,-1}};
	float4x2 wind[4] = {{{-1,-1},{-1,1},{1,-1},{1,1}},{{-3,-1},{-1,3},{1,-3},{3,1}},{{-1,-3},{-3,1},{3,-1},{1,3}},{{-3,-3},{-3,3},{3,-3},{3,3}}};

	//Initialization
	float2x2 R = 0;
	float2 r = 0;
	float4 d = 0;

	//Define weights
	float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
	lancz /= dot(lancz,4);
	float4 w = {1,1,1,0};

	//Calculate (local) autocorrelation coefficients
	for (int k = 0; k<4; k+= 1){
		float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
		float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
		R += w[k]*mul(transpose(C),C);
		r += w[k]*mul(y,C);
		d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
	}
	
	//Normalize
	float n = 24;
	R /= n; r /= n;

	//Calculate a =  R^-1 . r
	float e = 0.005;
	float2 a = solve(R+e*e*I,r+e*e/2.0);

	//Nomalize 'a' (prevents overshoot)
	a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);

	//Calculate result
	float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
	float4 c = mul(float1x2(a),x);

	//Fallback to lanczos
	float t = saturate(1-500*sqr(x[0]-x[1]));
	c += t*(d-mul(float1x2(1,1)/4.0,x));
	
	return c;//+float4(0,0.5,0.5,0);
}
NEDI-II:
Code:
sampler s0 : register(s0);
float4 p0 :  register(c0);

#define width  (p0[0])
#define height (p0[1])

#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))

#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))

#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))

//Conjugate residual 
float2 solve(float2x2 A,float2 b) {
	float2 x = 1/4.0;
	float2 r = b - mul(A,x);
	float2 p = r;
	float2 Ar = mul(A,r);
	float2 Ap = Ar;
	for (int k = 0;k < 2; k++){
		float a = min(100,dot(r,Ar)/dot(Ap,Ap));
		x = x + a*p;
		float2 rk = r; float2 Ark = Ar;
		r = r - a*Ap;
		Ar = mul(A,r);
		float b = dot(r,Ar)/dot(rk,Ark);
		p = r + b*p;
		Ap = Ar + b*Ap;
	}
	return x;
}

//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }

float4 main(float2 tex : TEXCOORD0) : COLOR {
	float4 c0 = tex2D(s0,tex);

	//Skip pixels on wrong grid
	if ((frac(tex.x*width/2.0)<0.5)&&(frac(tex.y*height/2.0)<0.5)) return c0;
	if ((frac(tex.x*width/2.0)>0.5)&&(frac(tex.y*height/2.0)>0.5)) return c0;
	
	//Define window and directions
	float2 dir[4] =  {{-1,0},{1,0},{0,1},{0,-1}};
	float4x2 wind[4] = {{{-1,0},{1,0},{0,1},{0,-1}},{{-1,2},{1,-2},{2,1},{-2,-1}},{{-1,-2},{1,2},{-2,1},{2,-1}},{{-3,0},{3,0},{0,3},{0,-3}}};

	//Initialization
	float2x2 R = 0;
	float2 r = 0;
	float4 d = 0;

	//Define weights
	float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
	lancz /= dot(lancz,4);
	float4 w = {1,1,1,0};

	//Calculate (local) autocorrelation coefficients
	for (int k = 0; k<4; k+= 1){
		float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
		float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
		R += w[k]*mul(transpose(C),C);
		r += w[k]*mul(y,C);
		d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
	}
	
	//Normalize
	float n = 24;
	R /= n; r /= n;

	//Calculate a =  R^-1 . r
	float e = 0.005;
	float2 a = solve(R+e*e*I,r+e*e/2.0);

	//Nomalize 'a' (prevents overshoot)
	a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);

	//Calculate result
	float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
	float4 c = mul(float1x2(a),x);

	//Fallback to lanczos
	float t = saturate(1-500*sqr(x[0]-x[1]));
	c += t*(d-mul(float1x2(1,1)/4.0,x));
	
	return c;//+float4(0,0.5,0.5,0);
}

Last edited by Shiandow; 25th January 2015 at 14:29. Reason: Updated information, added SuperChromaRes shaders.
Shiandow is offline   Reply With Quote
Old 4th June 2014, 21:05   #2  |  Link
TheElix
Registered User
 
Join Date: May 2010
Posts: 236
Shader implementation of the NEDI algorithm

Quote:
Originally Posted by Shiandow View Post
Funny you should say that. I've just succeeded in implementing the NEDI algorithm (the one by Xin Li et al. not the nnedi3 algorithm MadVR uses) in a shader. This made it run at a speed similar to, if not faster than, Jinc3. Without too large a loss in quality compared to nnedi3.

Here it is compared to some other algorithms:
Nearest
Jinc3
nnedi3 (32 neurons)
NEDI

I was hoping that this might be useful as a faster alternative to nnedi3.
This is interesting, I'd like to give it a try. Can you share a link to your thread?
TheElix is offline   Reply With Quote
Old 4th June 2014, 23:21   #3  |  Link
ryrynz
Registered User
 
ryrynz's Avatar
 
Join Date: Mar 2009
Posts: 3,528
Quote:
Originally Posted by Shiandow View Post
I was hoping that this might be useful as a faster alternative to nnedi3.
Wow.

NEDI destroys Jinc giving a much more natural presentation. Both Jinc and nnedi3 are very artificial looking in comparison and it's the same speed as Jinc? Could it possibly be even faster if it was coded within MadVR?

I actually prefer the look of NEDI here to MadVR's nnedi3 too, It's just too strong (I would like to make better comparisons using a full screen images though)

Last edited by ryrynz; 5th June 2014 at 00:02.
ryrynz is offline   Reply With Quote
Old 4th June 2014, 23:58   #4  |  Link
Motenai Yoda
Registered User
 
Motenai Yoda's Avatar
 
Join Date: Jan 2010
Posts: 709
I still prefer nnedi3
__________________
powered by Google Translator
Motenai Yoda is offline   Reply With Quote
Old 5th June 2014, 00:27   #5  |  Link
Nevilne
Registered User
 
Join Date: Aug 2010
Posts: 134
Looks quite beneficial for madvr.
Was there ever a nedi plugin for avisynth by the way?
Nevilne is offline   Reply With Quote
Old 5th June 2014, 00:38   #6  |  Link
Shiandow
Registered User
 
Join Date: Dec 2013
Posts: 753
EDIUpsizer and FastEDIUpsizer by tritical are apparently based on the NEDI algorithm. This later developed into nnedi3 but for some reason the NEDI algorithm was abandoned at some point.
Shiandow is offline   Reply With Quote
Old 5th June 2014, 00:43   #7  |  Link
ryrynz
Registered User
 
ryrynz's Avatar
 
Join Date: Mar 2009
Posts: 3,528
Faster than Jinc? I enabled all four of these in the right order and it's delivering a few frames per second, not sure why as both CPU and GPU usage are fairly low. i5 3570K, HD 4600, windows 7.

Is it possible this is only any good on Nvidia or AMD hardware?

Last edited by ryrynz; 5th June 2014 at 00:45.
ryrynz is offline   Reply With Quote
Old 5th June 2014, 00:50   #8  |  Link
Shiandow
Registered User
 
Join Date: Dec 2013
Posts: 753
Well, it does need a lot of texture calls, then again so does Jinc. What program did you use?

Edit: You can also try making the window smaller by changing the line:
Code:
	float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
	lancz /= dot(lancz,4);
	float4 w = {1,1,1,0};
to
Code:
	float4 lancz = {0.328511,-0.0365013,0,0};
	lancz /= dot(lancz,4);
	float4 w = {1,1,0,0};
or even
Code:
	float4 lancz = {1,0,0,0};
	lancz /= dot(lancz,4);
	float4 w = {1,0,0,0};

Last edited by Shiandow; 5th June 2014 at 01:10.
Shiandow is offline   Reply With Quote
Old 5th June 2014, 01:48   #9  |  Link
leeperry
Kid for Today
 
Join Date: Aug 2004
Posts: 3,477
Oh wow, very impressive! Sharp, yet not quite artificial looking like NNEDI3 and this will also make the AMD interop lag a non-issue. for sharing, can't wait for madshi to add it to mVR
leeperry is offline   Reply With Quote
Old 5th June 2014, 04:43   #10  |  Link
pie1394
Registered User
 
Join Date: May 2009
Posts: 212
Just looking forward to see if madshi has time to integrate your implementation into madVR!

About the resolution enhancement (i.e. sharpness) of your image samples, my eyes feel :

Nearest >> NNEDI3_32 > NEDI > Jinc3 (+AR or not?)

Of course it definitely causes serious jaggy / unstable edges on motion objects with Nearest scaling mode.

In fact sometimes I still notice that with Luma NNEDI3_32 mode. Luma NNEDI3_64 mode solves that to give more stable motion like Jinc3AR and even more sharper image, but the cost is somewhat too high for HD contents. It will be great if NEDI allows to preserve better original resolution + same motion edge stability than Jinc3AR while it maintains the similar cost.

ps: My TV is Sony 65" HX920 with reality creation option (i.e. super-resolution function) at 20%. But it is still able to tell some difference among different scaling options in madVR. There is no need to say, madVR's Lanczos4_AR, Jinc3_AR, NNEDI3 options have better performance than the ability of TV set's scaler.

Last edited by pie1394; 5th June 2014 at 04:45.
pie1394 is offline   Reply With Quote
Old 5th June 2014, 05:29   #11  |  Link
StinDaWg
Registered User
 
Join Date: Jan 2014
Posts: 216
How do you use this in MPC-HC?
StinDaWg is offline   Reply With Quote
Old 5th June 2014, 05:31   #12  |  Link
burfadel
Registered User
 
Join Date: Aug 2006
Posts: 2,229
Yeah it would be good if it were incorporated into MadVR, NNEDI3 just doesn't seem practical for everyday use. It's not that the output of NNEDI3 is bad (although maybe a little overdone as some people have pointed out), it's the efficiency of the actual processing. NNEDI3 requires a fair bit of processing power, which in turn requires a fair bit of electricity. If this NNEDI shader can use 'as little' amount of electricity as Jinc, with the quality close to NNEDI3, then that is a very good thing! This is even if the processing of a pixel twice can't be resolved. If it can be worked out, it would require even less processing power...
burfadel is offline   Reply With Quote
Old 5th June 2014, 08:03   #13  |  Link
madshi
Registered Developer
 
Join Date: Sep 2006
Posts: 9,140
I have implemented a fair number of algorithms in Delphi/Pascal, just to try them out. The original NEDI is one of them, also the Zhao-Xin Li improvement of the original NEDI algorithm and the iNEDI algorithm. I've also tried MEDI, ICBI and several others. In some images NEDI looks great. But there are also a lot of images where it looks totally unusable, IMHO. Which is why I never even considered using it in madVR.

But maybe my NEDI implementation was buggy, I don't know. If you guys want to make sure, try all the test images from the following thread:

http://forum.doom9.org/showthread.php?t=145358&page=4

I think after trying all of them you'll probably agree with me that it's not a suitable algorithm for madVR due to heavy artifacts. If you do still like it, please post all the 4x upscaled NEDI images of all those test images from the linked thread here, and maybe I'll reconsider. In any case, thanks to Shiandow for your efforts!

P.S: Here's the iNEDI paper which showcases some of the NEDI problems:

http://www.tecnick.com/pagefiles/pap...VISAPP2008.pdf

Please note that the iNEDI authors "replaced" iNEDI later with the ICBI algorithm. And ICBI is worse than Jinc AR, IMHO. Basically the NEDI algorithm and all its improvements produce directional artifacts and a "fractal like" look. On the positive side, they can be quite sharp. All the newer algorithms which are trying to reduce the NEDI artifacts, are much much slower and generally make the image look less like NEDI and get nearer to Jinc/NNEDI3. Please also note that NNEDI3 while having a similar name is a *completely* different algorithm compared to NEDI. IMHO, NNEDI3 is so much better than NEDI etc that it's not even funny. At least when comparing a lot of different images. The key reason is that NNEDI3 only has very few artifacts. NEDI is *FULL* of artifacts.

Last edited by Guest; 5th June 2014 at 11:15. Reason: make links clickable
madshi is offline   Reply With Quote
Old 5th June 2014, 08:20   #14  |  Link
madshi
Registered Developer
 
Join Date: Sep 2006
Posts: 9,140
P.S: Also look here:

http://www.general-cathexis.com/manual2/#anchor8

Scroll down a bit until you get the table with "Artifact Avoidance, Relative Times, and Visual Comparisons". In that table "Xin Li" is the original NEDI algorithm. I hope you'll agree with me that with this test image, NEDI produces an extremely artificial looking image. Looks like watercolor to me, or some other sort of "art" distortion.

Last edited by Guest; 5th June 2014 at 11:15. Reason: make link clickable
madshi is offline   Reply With Quote
Old 5th June 2014, 11:42   #15  |  Link
burfadel
Registered User
 
Join Date: Aug 2006
Posts: 2,229
Madshi, are you talking about NEDI or NNEDI? They're not the same thing, apparently!
burfadel is offline   Reply With Quote
Old 5th June 2014, 11:53   #16  |  Link
vivan
/人 ◕ ‿‿ ◕ 人\
 
Join Date: May 2011
Location: Russia
Posts: 643
Of course he knows what he is talking about...
vivan is offline   Reply With Quote
Old 5th June 2014, 13:22   #17  |  Link
Shiandow
Registered User
 
Join Date: Dec 2013
Posts: 753
Quote:
Originally Posted by madshi View Post
P.S: Also look here:

http://www.general-cathexis.com/manual2/#anchor8

Scroll down a bit until you get the table with "Artifact Avoidance, Relative Times, and Visual Comparisons". In that table "Xin Li" is the original NEDI algorithm. I hope you'll agree with me that with this test image, NEDI produces an extremely artificial looking image. Looks like watercolor to me, or some other sort of "art" distortion.
Indeed NEDI does look horrible on that image. However the shader I created seems to avoid quite a lot of the artefacts (but not all). To make the shader more stable I've had to add a slight preference for 'simpler' solutions which also prevents it from overfitting.

Anyway I've tested it on the images from this page, I think it performs reasonably well, although it might be better to fall back to lanczos somewhat more aggressively to avoid some of the artefacts.

Car show.

Castle.

Cat.

Clown.

Flowers.

Lighthouse.

Meter.

"Wc".

Pixel art.
Shiandow is offline   Reply With Quote
Old 5th June 2014, 13:43   #18  |  Link
Procrastinating
Registered User
 
Procrastinating's Avatar
 
Join Date: Aug 2013
Posts: 71
Some of those tests still feel a little "oil painty" for me. If you can deliver any consistent results over jinc/lanczos however, I don't see any reason why it shouldn't be incorporated into madVR. Many people seem to have hardware that is only just, or just under the required performance for NNEDI3 16. It seems like it could at least make NNEDI3 16 redundant.

Last edited by Procrastinating; 5th June 2014 at 13:46.
Procrastinating is offline   Reply With Quote
Old 5th June 2014, 14:49   #19  |  Link
madshi
Registered Developer
 
Join Date: Sep 2006
Posts: 9,140
Ok, it seems Shiandow's modifications do reduce the artifacts quite nicely, compared to the original NEDI algorithm, but I still don't consider it good enough for my taste yet. E.g. compare the Castle image:

NEDI
NNEDI3

It's not even in the same class. NNEDI3 is like 10 times better with this image. NNEDI3 is sharper, more focused, has less ringing and much less directional/weird artifacts. I think I would also very much prefer Jinc3 AR over NEDI - with this image at least.

The problem is this: If you just want to upscale one specific photograph/image, you can play with different algorithms and pick one which looks best for just that image. But madVR is about real time video playback with all kinds of different videos/scenes/images. So I need algorithms which always looks at least decent. I can't use algorithms which look great on some specific images but look horrible on some other images. I don't think NEDI is good enough for general purpose madVR use due to the heavy directional artifacts in many images. Of course that's only my personal opinion. And it only applies to the current version of Shiandow's shader...

Last edited by madshi; 5th June 2014 at 14:51.
madshi is offline   Reply With Quote
Old 5th June 2014, 17:04   #20  |  Link
Shiandow
Registered User
 
Join Date: Dec 2013
Posts: 753
Well, there's not much I can do about the getting a sharper result, the way NEDI works just forces some lines to get blurred (since there's no way to tell on which side of the edge you are, at least not by looking at a small part of the image). I might be able to prevent some of the artefacts, but likely not all. And it's probably possible to prevent some ringing by falling back to bicubic instead of lanczos.

I would like to mention that most artefacts only become problematic when you use NEDI twice, when you only use NEDI once they aren't that much of a problem.
Shiandow is offline   Reply With Quote
Reply

Tags
chromanedi, nedi, shader, superres, upscaling

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 16:40.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2022, vBulletin Solutions Inc.