Search code examples
visual-studio-2017directx-11hlsldirectx-9

How to compile hlsl shaders multiple times in visual studio?


I have HLSL shaders added to my Visual Studio project and they're getting compiled automatically to cso files as part of the build process. The problem which I'm facing is, that I need to compile them multiple times using different Shader models because i.e. "/4_0_level_9_3" works on DirectX 11, but not on DirectX 9, while "/3_0" only works on DirectX 9 but not on DirectX 11.

Adding the same files more than once to the Visual Studio project is not working and I would like to avoid copying the HLSL source files as it increases maintenance efforts and potential error causes. I can't create separate targets/configuration in Visual Studio to achieve this either, because I need to support both DirectX versions in the executable (switchable at runtime).

Is there any way to specify multiple compilations (different shader models and different output file) for a single HLSL file in Visual Studio?


Solution

  • Put your shader code into an .hlsli file, add that to your project. Create for each shader and model combination an .hlsl file which does a #include of your .hlsli file. Add each .hlsl to your project and set the file settings appropriately.

    File 1 (set to exclude from build)

    // MyShader.hlsli
    
    PS_INPUT VertexShader( VS_INPUT input )
    {
    ...
    }
    
    float4 PixelShader( PS_INPUT input)
    {
    ...
    }
    

    File 2 (set to build as a Vertex Shader, Shader Model 9_3, Entry-point VertexShader)

    // MyShader_VS.hlsl
    
    #include "MyShader.hlsl"    
    

    File 3 (set to build as a Pixel Shader, Shader Model 9_3, Entry-point PixelShader)

    // MyShader_PS.hlsl
    
    #include "MyShader.hlsl"    
    

    File 4 (set to build as a Vertex Shader, Shader Model 4.0, Entry-point VertexShader)

    // MyShader_VS4.hlsl
    
    #include "MyShader.hlsl"    
    

    File 5 (set to build as a Pixel Shader, Shader Model 4.0, Entry-point PixelShader)

    // MyShader_PS4.hlsl
    
    #include "MyShader.hlsl"    
    

    Note that you can make life a little easier by manually editing your vcxproj file with a text editor. Look for the Label="UserMacros" and then in the ItemDefinitionGroup for each configuration right after that add a section for <FXCompile> to set better defaults (rather than 4.0_level_9_1):

    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Link>
    ...
    </Link>
    <ClCompile>
    ...
    </ClCompile>
    <FXCompile>
      <ShaderModel>4.0_level_9_3</ShaderModel>
    </FXCompile>
    

    Unless you are specifically targeting Windows XP systems, there's not much value in using the legacy Direc3D 9 API at all. Just use DirectX 11 Feature Level 9.3+ to target Shader Model 2.0/3.0 era video cards. The main value of Shader Model 3.0 was vertex texture fetch which was never implemented by one of the major vendors anyhow. The 4_0_level_9_3 profile already builds the shader as both 2.0 and 4.0 in the same blob.