Converting DX9 shaders to DX11

Welcome to our brand new Clickteam Community Hub! We hope you will enjoy using the new features, which we will be further expanding in the coming months.

A few features including Passport are unavailable initially whilst we monitor stability of the new platform, we hope to bring these online very soon. Small issues will crop up following the import from our old system, including some message formatting, translation accuracy and other things.

Thank you for your patience whilst we've worked on this and we look forward to more exciting community developments soon!

Clickteam.
  • DX9 effects files in Fusion consist of 2 files:

    .xml => effect definition
    .fx => DX9 effect file

    In Fusion 2.5+ you can also use DirectX11 shaders, this adds 2 or 3 files:

    .hlsl -> dx11 HLSL file
    .fxc -> DX11 compiled shader (compiled with the fxc.exe from the Microsft SDK)
    .premultiplied.fxc -> optional, DX11 compiled shader that will be used in "premultiplied" mode


    How to create a .hlsl file from a .fx file

    Both files are very similar. What to change:


    1. Pixel shader output / input

    Replace COLOR0 by SV_TARGET either in the PS_OUTPUT structure if you use one, or in the main shader function otherwise, like this:

    Code
    struct PS_OUTPUT
    {
        float4 Color   : SV_TARGET;
    };

    or

    Code
    float4 ps_main(in float2 In : TEXCOORD0) : SV_TARGET


    - Input: you should use the following input structure:

    Code
    struct PS_INPUT
    {
      float4 Tint : COLOR0;
      float2 texCoord : TEXCOORD0;
    };

    So in the end your main shader function should look like:

    Code
    PS_OUTPUT ps_main( in PS_INPUT In )

    or:

    Code
    float4 ps_main( in PS_INPUT In ) : SV_TARGET


    2. Textures

    Replace the main texture:

    Code
    sampler2D Tex0;

    by:

    Code
    Texture2D<float4> Tex0 : register(t0);
    	sampler Tex0Sampler : register(s0);

    Do this for additional textures too, use the same register index as the one in the .fx (or 0 for the object's texture). For example if you use a background texture:

    Code
    Texture2D<float4> bg : register(t1);
    	sampler bgSampler : register(s1);


    In the HLSL code, replace tex2D(Tex0, xy) by Tex0.Sample(Tex0Sampler, xy);


    3. Parameters

    Move all the parameters parameters in a cbuffer structure (the parameters that are defined in the shader XML file):

    Code
    cbuffer PS_VARIABLES : register(b0)
    {
    	// [b]IMPORTANT: the parameters must be in the same order as in your XML file[/b]
    	float scale;
    	int coef;
    	float4 color;
    };


    4. If the shader uses fPixelWidth and fPixelHeight, add this:

    Code
    cbuffer PS_PIXELSIZE : register(b1)
    {
    	float fPixelWidth;
    	float fPixelHeight;
    };

    5. Multiply the texture color by In.Tint (= RGBA coefficient in the object properties) when you read from the texture:

    Code
    float4 color = Tex0.Sample(Tex0Sampler, xy) * In.Tint;

    (adjust to your code)

    6. Finally delete the technique section, you don't need it.


    How to build the .hlsl file to .fxc file

    Use the tool fxc.exe included in recent versions of the Microsoft SDK (for example a SDK that is installed with VS2017) to compile your shader to a .fxc file, this is the file used by Fusion.

    You can use Please login to see this link. that was taken and modified a bit from MS DirectXTK to build your shader. Make sure the local pathname of fxc.exe is correct in the batch file (in the case it can't be automatically determined) and replace ShaderTest by the name of your shader. The line that compiles your shader is:

    Code
    call :CompileShaderHLSL "ShaderTest" ps ps_main

    This line compiles your shader with ps_main as entry point.

    Replace CompileShaderHLSL CompileShaderHLSL4 if needed (like register limits etc). And replace ps_main if you use another name.

    The second CompileShaderHLSL line compiles the ps_main_pm function to a .premultiplied.fxc file. See below. Comment it out if you have no premultiplied version.


    Samplers

    Unlike .fx file, you cannot define sampler states in the DirectX 11 .hlsl files used by Fusion. If you need specific sampler states in DirectX 11 mode, you can define the in the XML file of your effect (requires build 292.6 or above). Just add sampler sections like this:

    <sampler>
    <index>register index of the sampler</index>
    <filter>Filtering method, can be point or linear (don't specify a filter member if you want to keep Fusion's mode)</filter>
    <addressU>U address mode, can be clamp, wrap, mirror, border (default = clamp)</addressU>
    <addressV>V address mode, can be clamp, wrap, mirror, border (default = clamp)</addressV>
    <bordercolor>border color (RGBA integer value, high order byte = alpha, low order byte = red)</bordercolor>
    </sampler>

    For example:

    <sampler>
    <index>0</index>
    <filter>point</filter>
    <addressU>wrap</addressU>
    <addressV>wrap</addressV>
    </sampler>


    Premultiplied mode

    2.5+ has a new premultiplied option. When this option is selected, the RGB values of the images (and various surfaces) are multiplied with their alpha value. Some shaders work the same with or without this option, others don't. If your shader needs a premultiplied version, compile this version as .premultiplied.fxc file. When Fusion builds an application that has the Premultiplied option, it first tries to find a .premultiplied.fxc file instead of a .fxc file. If it can't find it, it takes the .fxc file.

    As you can see in the already converted effects, some of them have both a ps_main and a ps_main_pm functions. The second one is the premultiplied version, this is the one that is built to a .premultiplied.fxc file by the batch file above.

    The simplest way to convert a shader to premultiplied is to (1) demultiply the source color (divide the rgb by the alpha), (2) apply the normal shader, (3) multiply the output rgb by its alpha. It's what most converted shaders do for the moment.


    Hopefully this quick guide is not too obscure and has no mistake (I'm sure it has)...

    Edited once, last by Yves (April 19, 2019 at 8:50 PM).

  • I'm having difficulty in porting shaders that sample interpolated sub-pixels from their textures. I'm trying to port over Looki's background offset shader, and have gotten the structure and syntax over to DX11, but it appears that it won't allow for small offsets that would sample partially between two pixels, only moving an offset of 1 integer pixel at a time.
    I'm guessing this is some kind of issue with the sampler types, but even trying to set up a sampler with MIN_MAG_MIP_LINEAR set explicitly as a state, it won't interpolate

    to isolate the issue and make it more generalized, I've created a simple shader example that shows the difference between DX9 and DX11

    Please login to see this attachment.

    If anyone knows how I could resolve this to interpolate instead of using discrete sampling, I could port over some useful shaders. Looking at other posts, I think a few people are using the offset shader alone

    also I should say, I think this is distinct from the issue of dx11 shifting over all pixels by 0.5/0.5, because that wouldn't explain the lack of interpolation as you set the offset

  • oh! I think I might have found a 'solution'. I changed the tex0 sampler state from being set to register s0 to s1, and that used bilinear filtering.
    I'm trying to understand, are there default samplers set in register s0, s1, s2.. etc, or at least, just in register s0? It would be nice to know what the settings are for each register, or maybe I'm just instantiating a new register with default values (set to linear) when I set 's1'? But at any rate, it seems like the sampler in s0 is set to use MIN_MAG_MIP_POINT

    /e and in the background shader I have to set the texture to s2... presumably both s0 and s1 are set when the backgroundshader parameter = 1?
    I've got workable solutions now, I'm just worried I don't understand what's going on

    Edited 2 times, last by Pixelthief (April 5, 2019 at 1:48 AM).

  • If we successfully convert a 3rd-party shader that's distributed free (eg. Looki's large Shader Pack), what should we do? Should we upload them here for others? Or send to Clickteam? Or do nothing and leave it up to the original creator to update them 'officially'?

    Please login to see this link.
    My Fusion Tools: Please login to see this link. | Please login to see this link. | Please login to see this link.

  • Thank you Yves for the guide, it took me a few hours (i'm pretty noobish at this, i need more shader fundamentals) to understand and port my custom shaders.

    My shaders are quite simple (like just color swapping/combining + alpha channels) but I just couldn't get the result with the regular fxc, had to use the premultiplied way.
    Trying to set alpha channels correctly in shaders so you can use Fusion's transparency effect along with them is really hard for me... Feels more about luck than logic in my case ^^'

  • If we successfully convert a 3rd-party shader that's distributed free (eg. Looki's large Shader Pack), what should we do? Should we upload them here for others? Or send to Clickteam? Or do nothing and leave it up to the original creator to update them 'officially'?

    You can send them to Clickteam, I'll put them in the 2.5+ installer and Fusion update patchs, they installs the DX11 files for installed effects.

  • oh! I think I might have found a 'solution'. I changed the tex0 sampler state from being set to register s0 to s1, and that used bilinear filtering.
    I'm trying to understand, are there default samplers set in register s0, s1, s2.. etc, or at least, just in register s0? It would be nice to know what the settings are for each register, or maybe I'm just instantiating a new register with default values (set to linear) when I set 's1'? But at any rate, it seems like the sampler in s0 is set to use MIN_MAG_MIP_POINT

    /e and in the background shader I have to set the texture to s2... presumably both s0 and s1 are set when the backgroundshader parameter = 1?
    I've got workable solutions now, I'm just worried I don't understand what's going on

    s0 = object texture
    s1 = first texture parameter if any
    s2 = second texture parameter if any
    etc.

    and if you use the background texture, it will be inserted at the index defined in the XML file. For example if you set BackgroundTexture to 1 in the XML file it will use s1, in this case this will give:

    s0 = object texture
    s1 = background texture
    s2 = first texture parameter if any
    etc.

    If you want to change the sampler states I'll probably need to add options in the XML file for this, IIRC you can't change the sampler state in DX11 HLSL files, unlike DX9 effect files.

    Edited once, last by Yves (April 5, 2019 at 10:35 AM).

  • okay thanks that explains it. The sampler states for the textures loaded via MMF use point filtering which makes sense for output, Looki's background offset just relied upon it for a smooth heightmap, so I should be safe in using an open register. I guess same point as Volnaiskra, I'll convert some 3rd party shaders and post them for you later today

  • Alright I've uploaded the shaders I use in my project. I lost track of which ones were already updated with the DLC and which I converted, so I'm just including all the ones on my list (pretty sure lens/mask were already updated). These should all more or less have the same functionality in DX11 as DX9, but I might caution there might be a few differences like not using interpolated colors (aliased colors instead of blur) and I chopped off some unnecessary parameters from the XML files of a few that didn't use them. I don't know which shaders were made by whom, so all credit to original writers and whatever license they had
    I think several of these are shaders I made and never shared, and they probably don't include any documentation, I was just using them ad hoc

    Also, please back up any of your original .fx / .xml files before using these in case any of them aren't compatible, so you can revert them

    Please login to see this attachment.

    included are;
    Complex Software's Underwater Effect
    Lens
    Nobu's Texture Overlay
    Background Offset
    Background Offset + Ripple / Fade
    PT_RotateNoFade
    Reflection Filter
    Simple Mask
    Squeeze / Rotate
    Squeeze / Rotate Background Filter
    Fade to Black/White
    Zoom Water

  • Can someone convert the Saturation shader to dx11? I got lost halfway through.

    sure thing, this should work;
    Please login to see this attachment.

    keep in mind that version will also work for any RGB coefficient or blend coefficient on the object using the shader, unlike the DX9 version, so it will look different if you use RGBA on the object (you probably don't, so you wouldn't have to mind that. But having the rgba modifier means you could also slightly color the background like a sepia filter and smoothly fade in the shader, so I thought it was worth including)

    Edited once, last by Pixelthief (April 7, 2019 at 4:10 PM).

  • sure thing, this should work;
    Please login to see this attachment.

    keep in mind that version will also work for any RGB coefficient or blend coefficient on the object using the shader, unlike the DX9 version, so it will look different if you use RGBA on the object (you probably don't, so you wouldn't have to mind that. But having the rgba modifier means you could also slightly color the background like a sepia filter and smoothly fade in the shader, so I thought it was worth including)

    Very cool, thank you!!

    Please login to see this link.
    Please login to see this link.|Please login to see this link.|Please login to see this link.

  • A shader that I also have problem:
    Please login to see this link.
    If you could look, it would do me a great service.

    that ones not so simple, it comes out to be 79 operations in HLSL when I compile it, but its limited to 64 operations, so it would take some optimization
    I'm not 100% sure this will work the same, but I simply deleted all its fancy 'check to see if its in the box' code and instead just bounded the coordinates it will sample from at [0,1]
    that should work, right?

    Please login to see this attachment.

  • I tried to convert my shader...
    I edited my script and did all requested replacements...

    But the true nightmare start with fxc.exe....
    I installed Visual Studio Community 2019 and 2017 with a lot of random options and huge packages but I never found fxc.exe...
    What I need to install this legendary SDK ?

    There are a download link and detailed procedure somewhere ?

    Thank you for help

    Please login to see this link.
    Please login to see this link.

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!