English Amiga Board Amiga Lore


Go Back   English Amiga Board > Support > support.WinUAE

 
 
Thread Tools
Old 05 January 2017, 10:04   #1
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
WIP: Sharp_Bilinear_Simple filter (finally integer pre-scale!)

EDIT3: Another new version. Automatic integer prescale factor calculation is finally correct. Shader model reduced to v1.0 vertex, v2.0 pixel. This only works with latest winuae beta: http://www.winuae.net/files/b/winuae.7z

EDIT: New version. No need to adjust the prescalefactors anymore, it is done automatically now. The old version has been renamed to "_old.zip"

NOTE: There's still a problem making the integer pre-scale not quite perfect. This is due to a NULL filter discrepancy issue. I have started a new thread. Once that is fixed, I will post another update.

Finally, after I got it to work for UAE4All2 on the Vita, I now managed to make a "sharp_bilinear_simple" filter for WinUAE that does what I have always hoped to have in WinUAE: a perfect largest possible integer pre-scale followed by the bilinear scaling of only the remainder.

This gives the best sharp pixels with minimum blurring, and no other artefacts even if your output size is not an integer multiple of the Amiga resolution.

A side effect of this is that there's no real need for using line doubling or superhires just to get sharp pixels. I turned mine off. Of course there might be other reasons to use those settings.

Attached here are
- the code in a box just for reference
- the zipped file to extract. The sharp_bilinear_simple.fx file should go in the plugins/filtershaders/direct3d folder
- Two example screenshots comparing my filter (sharp) to standard WinUAE bilinear scaling (blurry)
- A screenshot of the filter settings window. The bilinear setting being ON is important because of some amount of post scaling that happens.

Note: WinUAE is great and by far the best Amiga emulator out there, but the filter settings window must be the most confusing and obtuse part of the whole GUI. There are so many choices and numbers without labels

EDIT: Latest code shown using TARGETDIMS to find prescale factor automatically.
Code:
/*
   Author: rsn8887 (based on TheMaister)
   License: Public domain
   
   Version 5
   
   This is an integer prescale filter that should be combined
   with a bilinear hardware filtering (GL_BILINEAR filter or some such) to achieve
   a smooth scaling result with minimum blur. This is good for pixelgraphics
   that are scaled by non-integer factors.
   
   Changelog:
   Version 5: Fix broken prescale factor calculation (again)
   Version 4: Fix completely broken prescale factor calculation 
   Version 3: fix small shift and missing pixels
   Version 2: Automatic prescale factor	
   Version 1: First Release, manual prescale factor
*/

float4x4 WorldViewProjection	: WORLDVIEWPROJECTION;

float2 sourceSize : SOURCEDIMS;
float2 targetSize : TARGETDIMS;

texture sourceTex 	: SOURCETEXTURE;

sampler	sourceSampler = sampler_state
{
	Texture   = (sourceTex);
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	AddressU  = Clamp;
	AddressV  = Clamp;
};

string combineTechnique : COMBINETECHNIQUE =  "Sharp_Bilinear_Simple";

struct VS_OUTPUT
{
	float4 oPosition 	: POSITION;
	float2 oTexCoord 	: TEXCOORD0;
	float2 texelScaled : TEXCOORD1;
	float2 prescaleFactor : TEXCOORD2;
};

// Vertex Shader
VS_OUTPUT vShader (float3 pos : POSITION, float2 texCoord : TEXCOORD0)
{
	VS_OUTPUT OUT = (VS_OUTPUT)0;

	OUT.oPosition = mul(float4(pos,1.0f),WorldViewProjection);
	OUT.oTexCoord = texCoord;
	
	//This fixes the missing pixels on the top of the screen in WinUAE
	OUT.texelScaled = (texCoord*sourceSize)-0.5f;
	
	
	//find optimum integer prescale and pass it to the pixelShader
	OUT.prescaleFactor = floor(targetSize/sourceSize);	

	return OUT;
}

// Pixel Shader
float4 pShader ( in VS_OUTPUT inp ) : COLOR
{  
	//inp.texelScaled has already been multiplied by texture_size inside vertex shader
	float2 texelFloored = floor(inp.texelScaled);
	float2 s = frac(inp.texelScaled);

	float2 regionRange = 0.5f - 0.5f / inp.prescaleFactor;

	// Figure out where in the texel to sample to get correct pre-scaled bilinear.
	// Uses the hardware bilinear interpolator to avoid having to sample 4 times manually. 
	float2 centerDist = s - 0.5f;
	float2 f = (centerDist - clamp(centerDist, -regionRange, regionRange)) * inp.prescaleFactor + 0.5f;
	float2 modTexel = texelFloored + f;
   
	return float4(tex2D(sourceSampler, modTexel/sourceSize).rgb, 1.0f);   
}

technique Sharp_Bilinear_Simple
{
   pass P0
   {
     VertexShader = compile vs_1_0 vShader();
     PixelShader  = compile ps_2_0 pShader();
   }  
}
Attached Thumbnails
Click image for larger version

Name:	Sharp_Bilinear_Simple_Settings.PNG
Views:	80
Size:	74.2 KB
ID:	51579   Click image for larger version

Name:	bilinear.jpg
Views:	143
Size:	211.4 KB
ID:	51580   Click image for larger version

Name:	sharp_bilinear_simple.jpg
Views:	136
Size:	242.8 KB
ID:	51581  
Attached Files
File Type: zip Sharp_Bilinear_Simple_Filter.zip (1.8 KB, 15 views)

Last edited by rsn8887; 11 January 2017 at 23:10.
rsn8887 is offline  
AdSense AdSense  
Old 05 January 2017, 18:52   #2
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 2,482
Thanks very much!!!

I tried doing that over in this thread but my effort probably wasn't achieving the proper result since I never bothered to learn how to write shaders.

A couple of questions:
- Could this shader be modified to work with earlier ps/vs versions than 3.0?
- Is it necessary to initialise VS_OUTPUT OUT to 0 in vShader since you write all fields of it?

You wrote:
//If we knew the output size, this would work to always give the minimum blur:
//OUT.prescaleFactor = floor(output_size/texture_size);


At least when I experimented using a paint program to scale up then bilinear filter to the destination size, the result was marginally sharper with larger pre-scale factors. E.g. for 640-pixel input with 1024-pixel wide output, prescaling 3x or 4x before scaling down gave a slightly better result than 2x. (Should the commented-out line use ceil not floor?)
mark_k is offline  
Old 05 January 2017, 19:51   #3
hexaae
Registered User

hexaae's Avatar
 
Join Date: Jul 2006
Location: Italy
Age: 41
Posts: 740
I used to play with Null (Extra Settings: Point/Bilinear 1:1) filter for sharper pixels... selecting 'D3D:Sharp Bilinear Simple' will theoretically improve emulation performance?
hexaae is offline  
Old 05 January 2017, 20:03   #4
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Quote:
Originally Posted by hexaae View Post
I used to play with Null (Extra Settings: Point/Bilinear 1:1) filter for sharper pixels... selecting 'D3D:Sharp Bilinear Simple' will theoretically improve emulation performance?
No, performance will probably go down when enabling the filter. But the pixels should be sharper and/or show less pixel wobble. Depending on your drawing system (ddraw, d3d) The "null" setting and "point/bilinear 1:1" will result either in an image like my attached blurry one or in an image that's "perfectly sharp" but shows wobble.

Pixelwobble is when you have a slow scrolling game (or move the mouse pointer slowly in WB) and you see the pixel sizes "change" from square to rectangular. Some people don't mind that I hate it.

The Sharp_Bilinear_Simple will give you a sharp image like my attached sharper image without wobble. Notice there's still a bit of blur, unless your PC screen size is an exact multiple of the Amiga screen size and you use those factors in the shader.

Note this works only IF and ONLY IF your integer pre-scale numbers are not too large (depends on your PC screen size and Amiga screen size) see OP.

Last edited by rsn8887; 05 January 2017 at 20:20.
rsn8887 is offline  
Old 05 January 2017, 20:13   #5
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Quote:
Originally Posted by mark_k View Post
Thanks very much!!!

I tried doing that over in this thread but my effort probably wasn't achieving the proper result since I never bothered to learn how to write shaders.

A couple of questions:
- Could this shader be modified to work with earlier ps/vs versions than 3.0?
- Is it necessary to initialise VS_OUTPUT OUT to 0 in vShader since you write all fields of it?

You wrote:
//If we knew the output size, this would work to always give the minimum blur:
//OUT.prescaleFactor = floor(output_size/texture_size);


At least when I experimented using a paint program to scale up then bilinear filter to the destination size, the result was marginally sharper with larger pre-scale factors. E.g. for 640-pixel input with 1024-pixel wide output, prescaling 3x or 4x before scaling down gave a slightly better result than 2x. (Should the commented-out line use ceil not floor?)
- The initialization might be removed, not sure, I just followed the other examples. Notice anything in vertex shader should not cause a performance hit, it is only executed ONCE, not per pixel. That is why I intend to pre-calculate as much in there as possible and then parse it down to the pixelshader, so the pixelshader has to calculate as little as possible.

- It should be "floor", but that is not used. I know what you mean, in programs like MAME very large pre_scale works just fine and gives a very nice image. But from my tests with WinUAE and this shader, if the integer pre-scale is too large, e.g. anytime it results in a size _larger_ than the screen output size, the result looks absolutely horrible with a lot of pixel wobble. You'll notice immediately, just move the mouse pointer and see the wobble. If you see that, just decrease the numbers.

I wish I had access to the "screen size" or "output size" from within the shader, because then the integer factors could be automatically calculated to be optimum using that floor function.

- About shader model versions. You can just try replacing the
VertexShader = compile vs_3_0 vShader();
PixelShader = compile ps_3_0 pShader();
with
VertexShader = compile vs_2_0 vShader();
PixelShader = compile ps_2_0 pShader();
or
VertexShader = compile vs_1_0 vShader();
PixelShader = compile ps_1_0 pShader();

or other combinations Tell me what you find out. If the shader fails to compile you will just get a black screen (emulation will hang)
rsn8887 is offline  
Old 05 January 2017, 20:30   #6
Dunny
Registered User

Dunny's Avatar
 
Join Date: Aug 2006
Location: Scunthorpe/United Kingdom
Posts: 741
Many thanks for this. To think that we've had this particular type of scaling (pre-scale+bilinear) in Spectrum emulation for more than a decade, but it's only now that we're getting it for Amiga...

Better late than never, and this looks the business, it really does. Top job.
Dunny is offline  
Old 05 January 2017, 20:36   #7
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 42
Posts: 19,561
Quote:
Since WinUAE does not seem to expose the dimensions of the scaled picture to the shader
What is scaled picture? Final output resolution?
Toni Wilen is offline  
Old 05 January 2017, 20:56   #8
thellier
Registered User
 
Join Date: Sep 2011
Location: Paris/France
Posts: 148
Hello

>If we knew the output size, this would work to always give the minimum blur

WorldViewProjection (matrix) certainly store somewhere the window size (=output size) as this matrix is used to convert XYZ from GL space to screen space

Alain
thellier is offline  
Old 05 January 2017, 21:53   #9
thellier
Registered User
 
Join Date: Sep 2011
Location: Paris/France
Posts: 148
Something like that should works (sorry dont know this shading langage) :


float3 screencorner=float3(1,-1,1);

screencorner = mul(screencorner,WorldViewProjection);

output_size.x=screencorner.x;
output_size.y=screencorner.y;
thellier is offline  
Old 06 January 2017, 00:42   #10
hexaae
Registered User

hexaae's Avatar
 
Join Date: Jul 2006
Location: Italy
Age: 41
Posts: 740
Quote:
Originally Posted by rsn8887 View Post
No, performance will probably go down when enabling the filter. But the pixels should be sharper and/or show less pixel wobble. Depending on your drawing system (ddraw, d3d) The "null" setting and "point/bilinear 1:1" will result either in an image like my attached blurry one or in an image that's "perfectly sharp" but shows wobble.

Pixelwobble is when you have a slow scrolling game (or move the mouse pointer slowly in WB) and you see the pixel sizes "change" from square to rectangular. Some people don't mind that I hate it.

The Sharp_Bilinear_Simple will give you a sharp image like my attached sharper image without wobble. Notice there's still a bit of blur, unless your PC screen size is an exact multiple of the Amiga screen size and you use those factors in the shader.

Note this works only IF and ONLY IF your integer pre-scale numbers are not too large (depends on your PC screen size and Amiga screen size) see OP.
With 1:1 + null filter I eliminated that wobble effect (I can see better square pixels), with a very slight blur.
With 1:1 + Sharp Bilinear Simple is very close to previous, but not identical.
Attached Thumbnails
Click image for larger version

Name:	ArcadePool_Null.png
Views:	65
Size:	127.0 KB
ID:	51592   Click image for larger version

Name:	ArcadePool_SharpBilinearSimple.png
Views:	65
Size:	128.3 KB
ID:	51593  
hexaae is offline  
Old 06 January 2017, 00:42   #11
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Quote:
Originally Posted by thellier View Post
Something like that should works (sorry dont know this shading langage) :


float3 screencorner=float3(1,-1,1);

screencorner = mul(screencorner,WorldViewProjection);

output_size.x=screencorner.x;
output_size.y=screencorner.y;
No it doesn't work. I think all those are somehow scaled coordinates between 0 and 1 or -1 and 1 or something.

After googling this for another hour, it seems set: the ONLY way to get the screen size is to pass it into the shader from the main program (winUAE). Some environments have preset variables for this. I read about glFragCoord and wpos, and in Unity it is called _ScreenParams, but here in WinUAE we don't have it (yet ). Apparently d3d has VPOS but it only gives the current pixel coordinate in screen space, not the total height and width of the screen in pixels.

AFAIK this MUST be set from the host application and is not available in the shader itself.

So in short what we need somehow is the host screen size. For example if the user opens up WinUAE in fullscreen mode with a screen res of 800*600 (call it output_size), even if the WinUAE Amiga screen is only 640*200 (call that input_size). Right now, we have access to input_size from within the shader. It is called INPUTDIMS, SOURCEDIMS and float2(1/TEXELSIZE.x,1/TEXELSIZE.y). But there is no OUTPUTDIMS, SCREENDIMS or anything like that.

BTW: Shader languages and models must be the WORST documented things ever.
Best I found it http://http.developer.nvidia.com/CgT...chapter04.html
EDIT: Also found this MSDN site now:
https://msdn.microsoft.com/en-us/lib...ader_Variables
Spotty, but more useful. So yes all those constructs are scaled coordinates. The shader does not know about the screen_size.

Last edited by rsn8887; 06 January 2017 at 01:04.
rsn8887 is offline  
Old 06 January 2017, 00:46   #12
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Quote:
Originally Posted by hexaae View Post
With 1:1 + null filter I eliminated that wobble effect (I can see better square pixels), with a very slight blur.
With 1:1 + Sharp Bilinear Simple is very close to previous, but not identical.
I don't understand how that is possible, unless I misunderstand how NULL and 1:1 work. Null and 1:1 bilinear should cause HUGE blurring (and they do on my system). What is your Amiga screen size and Host screen size? maybe they are almost identical already? Superhires on, and line doubling on or something?

Last edited by rsn8887; 06 January 2017 at 00:56.
rsn8887 is offline  
Old 06 January 2017, 00:50   #13
hexaae
Registered User

hexaae's Avatar
 
Join Date: Jul 2006
Location: Italy
Age: 41
Posts: 740
Quote:
Originally Posted by rsn8887 View Post
I don't understand how that is possible, unless I misunderstand how NULL and 1:1 work. Null and 1:1 bilinear should cause HUGE blurring (and they do on my system). What is your Amiga screen size and Host screen size?
Attached my cfg and my filters dir.
http://www.filedropper.com/hexaaeprefsandfilters
hexaae is offline  
Old 06 January 2017, 01:10   #14
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Quote:
Originally Posted by Toni Wilen View Post
What is scaled picture? Final output resolution?
Winuae draws pixels into a direct3d texture that has certain dimensions (INPUTDIMS in the shader). Then it tells direct3d to display that texture at some scaled size on the host screen letting direct3d do that scaling. I need that scaled size passed into the shader. For example as OUTPUTDIMS, that's all.

It would be nice if it was automatically updating the new shader variable everytime the user changes it. For example if the user resizes the Window if UAE is in Windowed mode, such an update would be really cool because the sharp_bilinear_simple shader would auto adjust it's prescale values in real time keeping the picture always sharp.

For example if the user makes the window much smaller, and autoscale is on, OUTPUTDIMS might go from 1280*1020 down two 400*300 or some other value, as the window in which WinUAE is displayed becomes smaller. At the same time INPUTDIMS will stay constant because the original texture containing the amiga side pixels does not change.

But OUTPUTDIMS is not just the window size or screen size set in the display panel, because of aspect correction. WinUAE sometimes leaves large black borders, mostly on the left and right with widescreen displays. And those should not be part of the OUTPUTDIMS unless they are drawn into the direct3D texture, too. I think they are not, because the status line is not drawn in those borders usually. So those don't seem to be part of the texture that WinUAE is scaling onto the host display.

This OUTPUTDIMS (or however you want to call it) would also allow to test the shader very well, because at certain window sizes (2*INPUTDIMS,3*INPUTDIMS etc) the shader should produce a perfect image with no blurring since it will just do a perfect integer scaling and that's it.

Last edited by rsn8887; 06 January 2017 at 01:46.
rsn8887 is offline  
Old 06 January 2017, 07:15   #15
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
I think I have found a workaround using VPOS to access screencoords which seems to work in the shader.

However, I tested the shader and it does NOT give perfect integer scaled pixels at 2*, 3* etc. I am almost 100% sure it due to this problem:
https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

From what I gather, it looks like WinUAE might not be offsetting the quad by the required 0.5 pixels to align it with the screen pixels.

I made a quick NULL_TEST D3D filter to show this. The output should be identical to using the internal NULL filter, or the "none" filter. But it is not.

To better see the pixels in the tests, I am using "integer scaling" and "lores" without line doubling.
Attached Thumbnails
Click image for larger version

Name:	NULL_Internal.jpg
Views:	43
Size:	83.7 KB
ID:	51595   Click image for larger version

Name:	NULLTEST_D3D.jpg
Views:	48
Size:	82.8 KB
ID:	51596   Click image for larger version

Name:	Settings.jpg
Views:	29
Size:	277.9 KB
ID:	51597  
Attached Files
File Type: zip NULLTEST.zip (689 Bytes, 10 views)

Last edited by rsn8887; 06 January 2017 at 11:52.
rsn8887 is offline  
Old 06 January 2017, 14:59   #16
thellier
Registered User
 
Join Date: Sep 2011
Location: Paris/France
Posts: 148
>No it doesn't work. I think all those are somehow scaled coordinates between 0 and 1 or -1 and 1 or something.
Curious I thought it should works

perhaps it is
float3 screencorner=float3(1,-1,0);
or
float3 screencorner=float3(1,1,0);

the field Viewport.Size.x Viewport.Size.y is also supposed to contain the wanted size

Alain Thellier
thellier is offline  
Old 06 January 2017, 21:14   #17
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
No the only available semantics are those listed here:

https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

plus the ones in the WinUAE direct3d.cpp code here:

https://github.com/tonioni/WinUAE/bl...2/direct3d.cpp

(e.g. INPUTDIMS etc)

Your wvp gymnastics you proposed can never reveal the screensize those are all scaled coordinates always. There are tons of articles about it online, but very hard to find reliable info apart from NVidia shader tutorial and MSDN HLSL articles.

But anyways VPOS works just fine in the pixelshader. Causes a bit more overhead, but will work.

But unless I can get the D3D Nullfilter to give EXACTLY the same output with the same pixels as the internal Null Filter and the internal "none" filters, this is a fruitless endeavor and will never become a true sharp-bilinear with perfect integer prescale.

I am opening another thread to report that shader inconsistency between NULL filters.

Last edited by rsn8887; 06 January 2017 at 21:36.
rsn8887 is offline  
Old 06 January 2017, 21:34   #18
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
Admin request: Can an admin please add "WIP" to the thread title, until I have solved these issues? Thanks
rsn8887 is offline  
Old 06 January 2017, 22:01   #19
rsn8887
Registered User
rsn8887's Avatar
 
Join Date: Oct 2006
Location: USA
Posts: 726
UPDATE: I managed to calculate the optimum integer factors inside the shader using VPOS. As I said the prescaling could still be improved but it is very close to perfect integers. Once I figure out that NULL filter discrepancy, it might be possible to improve this shader further.

Here is the updated shader.
Attached Files
File Type: zip Sharp_Bilinear_Simple_Filter.zip (1.6 KB, 13 views)
rsn8887 is offline  
Old 06 January 2017, 22:13   #20
DamienD
Global Moderator

DamienD's Avatar
 
Join Date: Aug 2005
Location: London / Sydney
Age: 40
Posts: 8,989
Quote:
Originally Posted by rsn8887 View Post
Admin request: Can an admin please add "WIP" to the thread title, until I have solved these issues? Thanks
Done
DamienD is offline  
AdSense AdSense  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Cant scale WinUAE window big enough. Locutus support.WinUAE 2 16 August 2016 10:53
Integer pre-scale to reduce blurry pixels? rsn8887 support.WinUAE 4 10 April 2015 18:11
Scale Image with DataTypes? AGS Coders. System 10 13 March 2015 13:27
Image Scale x2 BippyM project.EAB 0 26 June 2013 23:36
Scale fullscreen mode independently? Neutrino support.WinUAE 1 12 March 2009 17:08

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 +2. The time now is 07:50.


Powered by vBulletin® Version 3.8.8 Beta 1
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Page generated in 0.27351 seconds with 12 queries