Do you wish Visual Studio would compile your HLSL files automatically for you? With this build task it can! This is especially useful for taking advantage of the new 3D Graphics support in Silverlight 5.
Grab the build task on the MSDN Code Gallery. Both the source code and the installer are included.
Building
To compile the solution you will need to install the DirectX SDK and the Visual Studio SDK. Afterwards you can open the ShaderBuildTask solution in Visual Studio to build.
Installing
The easiest way to install is to build and run ShaderBuildTaskSetup which will copy the build task to the GAC. The MSI installer is included in the download if you don’t want to build it.
Adding to a Project
Once installed, you can update a project to support the task by adding the following to the .csproj file after the Import element for Microsoft.Silverlight.CSharp.target.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<ItemGroup Condition="'$(BuildingInsideVisualStudio)'=='true'"> <AvailableItemName Include="VertexShader"> <Visible>false</Visible> </AvailableItemName> <AvailableItemName Include="PixelShader"> <Visible>false</Visible> </AvailableItemName> </ItemGroup> <UsingTask TaskName="ShaderBuildTask.ShaderCompile" AssemblyName= "ShaderBuildTask, Version=1.0.3072.18169, Culture=neutral, PublicKeyToken=44e467d1687af125" /> <Target Name="VertexShaderCompile" Condition="'@(VertexShader)' != '' " BeforeTargets="Build"> <ShaderCompile Sources="@(VertexShader)" ShaderProfile="vs_2_0" IntermediateOutputPath="$(IntermediateOutputPath)"> <Output TaskParameter="Outputs" ItemName="Resource" /> </ShaderCompile> </Target> <Target Name="PixelShaderCompile" Condition="'@(PixelShader)' != '' " BeforeTargets="Build"> <ShaderCompile Sources="@(PixelShader)" ShaderProfile="ps_2_0" IntermediateOutputPath="$(IntermediateOutputPath)"> <Output TaskParameter="Outputs" ItemName="Resource" /> </ShaderCompile> </Target> <PropertyGroup> <PrepareResourcesDependsOn>VertexShaderCompile;PixelShaderCompile; $(PrepareResourcesDependsOn)</PrepareResourcesDependsOn> </PropertyGroup> |
Visual Studio
From Visual Studio, you can change the Build Action of HLSL files to either PixelShader or VertexShader. After building the project, shaders will be compiled and included in the final assembly as a resource.
Use Application.GetResourceStream() to access resources, keeping in mind that the relative path of the containing folder is preserved. For example:
1 2 3 4 |
var earthVertexShader = VertexShader.FromStream( GraphicsDeviceManager.Current.GraphicsDevice, Application.GetResourceStream( new Uri(@"/SolarWind;component/Shaders/Earth_vs.vs", UriKind.Relative)).Stream); |
Parameters
The build task supports the following parameters.
- ShaderProfile – The profile to use (vs_2_0, ps_2_0, etc.). This is a required parameter.
- EntryPoint – The default entry point is “main” but can be overidden.
- PackMatrixRowOrder – A boolean that indicates whether to pack matrices in row major order (true) or column major (false).
- OptimizationLevel – This is only supported on new compilers (specify a value 0 to 3).
- Debug – Include debug information (default is false).
- ExportConstants – In addition to exporting a compiled shader, also export an XML file with information about the constants in the shader (default is true).
- IntermediateOutputPath – The path to export compiled shaders and constants to.
Constants Files
By default, constants are exported to an XML file with the same name as the compiled shader with “.constants” appended. This data can be used to map named variables on the application side to constant registers on the shader side.
A sample file snippet is below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?xml version="1.0" encoding="utf-8"?> <ShaderConstants FileFormatVersion="1.0" Version="2.0" Constants="5" Creator="Microsoft (R) HLSL Shader Compiler 9.29.952.3111"> <Constant Index="0" Descriptions="1"> <Description> <Name>TotalSeconds</Name> <RegisterSet>Float4</RegisterSet> <RegisterIndex>16</RegisterIndex> <RegisterCount>1</RegisterCount> <Rows>1</Rows> <Columns>1</Columns> <Elements>1</Elements> <StructMembers>0</StructMembers> <Bytes>4</Bytes> <Class>Scalar</Class> <Type>Float</Type> </Description> </Constant> <Constant Index="1" Descriptions="1"> <Description> <Name>ViewInverseMatrix</Name> <RegisterSet>Float4</RegisterSet> <RegisterIndex>12</RegisterIndex> <RegisterCount>4</RegisterCount> <Rows>4</Rows> <Columns>4</Columns> <Elements>1</Elements> <StructMembers>0</StructMembers> <Bytes>64</Bytes> <Class>Rows</Class> <Type>Float</Type> </Description> </Constant> … |
More Information
Original WPF shader build task by Greg Schechter and Gerhard Schneider. Updated by Aaron Oneal to include configurable properties for shader profile, entrypoint, matrix pack order, optimization level, debug, intermediate output path, and shader constants export.
There must be something wrong with the Msbuild thing, as my shaders are processed (I see files.ps/.vs and .constants in ./obj), but they are not embedded in assembly resources. Am I missing something?
Sorry that didn’t work for you. How did you verify the resources weren’t embedded in the final output assembly? If you can send a project to reproduce this to me I can take a look: aaron dot oneal at microsoft dot com
I found the bug, I have to delete the block :
false
false
and everything is good.
(to look at the resources, I use reflector).
Oups… the comment has been stripped its xml content.
it was the AvailableItemName elements that caused trouble
sorry but it does not work for me.
I compile but i have no vs and ps file in my project as resource. I use reflector to see that and the GetResourceStream returns null.
Even if a remove the AvailableItemName.
I saw the vs and ps file in the obj directory.
hum when a create a new project i have to change the csproj too
but i have the same problem.
Can you confirm your csproj file has this?
It sets up the dependency to compile the shaders as resources prior to the resource bundling. If you could place a repro project online somewhere (like SkyDrive) I can download it to check it out.
Also, what version of Visual Studio are you using?
I have the same issue. I verified that my project file contains that section.
You can take a repro project here: https://skydrive.live.com/redir.aspx?cid=69c8d3981feeac89&resid=69C8D3981FEEAC89!113
Update:
when I changed
to
it started working…
I mean:
<ItemGroup>
<None Include="Properties\AppManifest.xml" />
<PixelShader Include="Shaders\PixelShader.ps.hlsl" />
<VertexShader Include="Shaders\VertexShader.vs.hlsl" />
</ItemGroup>
to
<ItemGroup>
<PixelShader Include="Shaders\PixelShader.ps.hlsl" />
<VertexShader Include="Shaders\VertexShader.vs.hlsl" />
<None Include="Properties\AppManifest.xml" />
</ItemGroup>
Interesting, not sure why that fixed it but glad it did. I made a different change and it fixed it too.
When I moved the code the article describes after this line, the resources get included.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
I’ll update the article to be more specific.
I tried integrating this with the triangle sample, but VS is telling me “Unknown build error, ‘An item with the same key has already been added.’.
Make sure you don’t already have compiled shaders with the same name as resources in the project. If that’s not causing it, share out the project and I can take a look.
Yep, I think that was the problem. Thanks for creating this, dealing with shaders in project has always been a pain in the past.