Advertisement

Compiling pixel shaders for Silverlight

I saw a note on Twitter come through yesterday about building pixel shaders for Silverlight in Visual Studio.  The question, from @blamborn was:

Does anyone know if there is a Shader Effects BuildTask like the #WPF one here http://bit.ly/gCkNT only for #Silverlight?

I replied that you can use the same build task and thought I had written my work around on how to do that, but apparently I never clicked published somewhere along the line.  I recall doing some work for this for a presentation a while back on VSLive and started to write it up.  Here are hopefully some helpful knowledge around the subject.

Option 1: Compiling using DirectX Libraries

One option you can do is to use a pre-build command for your project in combination with the DirectX SDK.  What you really need out of the DirectX SDK is a tool called fxc.exe.  This is a compiler for the HLSL code for the pixel shader code you write.  The download is 500MB.  Yeah, big.  Once you have it installed you can put a pre-build command on your Visual Studio project with something like this:

   1: "C:\Program Files (x86)\Microsoft DirectX SDK (March 2009)\Utilities\bin\x86\fcx.exe" 
   2:     /T ps_2_0 /Fo "$(ProjectDir)ShaderEffect1.ps" "$(ProjectDir)ShaderEffect1.fx"

Now keep in mind your installation directory might be different, but you should get the gist of it.  The result of this command is that you’ll get a <Filename>.ps file that you will include in your project.  The .ps file, in fact, *IS* your pixel shader…that’s really the only thing your Silverlight project cares about!  The build command doesn’t automatically make it a part of your project though, so you’ll have to ensure that after it builds you use the “show all files” feature in Visual Studio and include it in your project.

Option 2: Using a build task

Another option is to use a build task in your project.  For Windows Presentation Foundation (WPF) developers, this is what is easiest and doesn’t require the massive 500MB download.  What is cool is that we can use the same build task for Silverlight.  Awesome right?  Well, yes and no.

It’s awesome that it works.  What is not awesome is the setup.  Allow me to walk you through my steps.  It’s a bit of hackery admittedly.  If anyone is a super Visual Studio extensibility wizard and wants to contribute knowledge to me on extending it to my liking, I’ll send you a virual Mt. Dew!  Here’s my steps otherwise.

Install the WPF Build tasks!!!  You can get them from here (Shader Effects Build Task and Templates).  Run the installer.  These steps assume you have them already!!!  You don’t need the templates, but if you want you can install them too – they are for WPF.  You’ll install my template as the next step.

1. Get the VS template I created for Silverlight Pixel Shaders.

I created an item template for Silverlight projects so that you can do Add Item…Silverlight Pixel Shader to your project.  Once you have this installed (just double-click on the VSI and follow the steps) you will see that option.

The template provides you with the right files that get added as well as follows the requirement for a pixel shader being a resource in your project.  You’ll notice after you add the item (let’s say you kept the default name) that the code will show:

   1: static ShaderEffect1()
   2: {
   3:     _pixelShader.UriSource = new Uri("/SilverlightApplication29;component/ShaderEffect1.ps", UriKind.Relative);
   4: }

This is the best practice for a pixel shader.  Note that my project name is SilverlightApplication29, but the template will use your projects name, of course.

2. Hackery 1: Open the **proj file for your Silverlight application in a text editor like notepad.

Yes, I know.  You are cursing me now.  I agree, if the tool (VS) is awesome why do I have to do this step?  I’ve been trying to understand myself how an item template can actually do all these things for you…again, if you are an extensibility expert, let me know!  But for now, bear with me.

In the **proj file (csproj or vbproj) add the following information right after the Import node in the file:

   1: <ItemGroup Condition="'$(BuildingInsideVisualStudio)'=='true'">
   2:     <AvailableItemName Include="Effect" />
   3:   </ItemGroup>
   4:   <UsingTask TaskName="ShaderBuildTask.PixelShaderCompile" AssemblyName="ShaderBuildTask, Version=1.0.3072.18169, Culture=neutral, PublicKeyToken=44e467d1687af125" />
   5:   <Target Name="EffectCompile" Condition="'@(Effect)' != '' ">
   6:     <PixelShaderCompile Sources="@(Effect)">
   7:       <Output TaskParameter="Outputs" ItemName="Resource" />
   8:     </PixelShaderCompile>
   9:   </Target>
  10:   <PropertyGroup>
  11:     <!-- Add effect compilation to the PrepareResourcesDependsOn so that the effect fx  get compiled before resources are collected -->
  12:     <PrepareResourcesDependsOn>EffectCompile;$(PrepareResourcesDependsOn)</PrepareResourcesDependsOn>
  13:   </PropertyGroup>

These properties enable you to see the “Effect” build task in the properties for your .fx files in the project.  Save the proj file and go back to Visual Studio.  You should be prompted to reload – go for it.  You may see a file named Effect with a warning icon on it.  For now, ignore it.  It’s admittedly an artifact of this hackery.  It will look like this:

Project solution explorer

Now that you have both of these steps you can add a new pixel shader (using my template of course).

3. Change the .fx file’s properties to Build Action: Effect.

Once you have added a shader library (using my template) to the project, select the .fx file (which is your HLSL code) and look at the properties dialog for the file.  Change the build action to the new item Effect.

Build action property

Build your project.

4. Hackery 2: Refresh the view all files and add to project

After the build, refresh the view all files feature and you should see your .ps file.  Right click on that and say Include in Project.  It should be included as a Resource build action automatically, but if it isn’t, make sure it is.

That’s it (as I say with a snarky smile).  I know it seems like some hacking….and it is.  But if you don’t want to download the DirectX SDK, you can still re-use the WPF build taks with a little project file modification.

If you don’t have a clue what a pixel shader is, check out this video.

Hope this helps!


This work is licensed under a Creative Commons Attribution By license.

  1. 9/2/2009 3:47 PM | # re: Compiling pixel shaders for Silverlight
    What would be really cool, would be the ability to load pixel shaders from a raw byte stream, like you can in WPF, rather than only from a precompiled resource.

    That way shaders could be dynamically generated and loaded at runtime - something for the wishlist, anyway.

    Andrew.
  2. 9/2/2009 3:52 PM | # re: Compiling pixel shaders for Silverlight
    Andrew - my head just exploded. Do you have a scenario where you would want to do this (instead of 'just because' of course) ;-0
  3. 9/3/2009 1:53 AM | # re: Compiling pixel shaders for Silverlight
    It came up once on the Silverlight forums, but I forget the actual scenario; it was enough to get me thinking of one though.

    Imagine something like Flikr, or Photosynth ( which is already using Silverlight ), but giving the user the ability to manipulate images using a simple scripting language.

    Such a language could be parsed by, say, the parsing tools provided by F# ( which work nicely in silverlight ) and emit pixel shader byte code. The DirectX DDK describes the format for the compiled pixel shaders.

    Everything is available to allow this to be done - apart from the PixelShader.SetStreamSource API.
  4. 9/9/2009 2:53 AM | # re: Compiling pixel shaders for Silverlight
    It works perfectly thanks! I don't konw why Microsoft never do this kind of things easier for desiners! To do an installer with this has no cost for them and it would be very good for let the designers get used to the tecnology.

    Thanks for your excellent work!
  5. 9/14/2009 7:16 PM | # re: Compiling pixel shaders for Silverlight
    Hi Tim,

    Thanks very much for the walk-through!

    You sparked an off-the-wall thought: does SL3 provide any way to "read" the computed shader output in SL 3.0?

    Thanks,
    David
  6. 9/15/2009 7:18 AM | # re: Compiling pixel shaders for Silverlight
    Tim thanks for this. I am just now try it. I have everything set up in my environment using Option #2 but I am hitting one snag. In step #4 "After the build, refresh the view all files feature and you should see your .ps file" I refresh, but do not see the .ps file listed in my solution. It is in the solution folder though. So I try to do an Add > Existing Item to my solution, which pull the file into VS, but when I try to build the solution I get:

    Error 1 Unknown build error, 'Item has already been added. Key in dictionary: 'shadereffect1.ps' Key being added: 'shadereffect1.ps'' SilverlightShadtest


    I tried it a few times and got the same thing. Any idea where I am going wrong?
  7. 9/15/2009 7:59 AM | # re: Compiling pixel shaders for Silverlight
    Never mind my last comment. Got it figured out. If I omit "Right click on that and say Include in Project" in step 4 all is good for me.
  8. 9/15/2009 2:26 PM | # re: Compiling pixel shaders for Silverlight
    David -- help me understand what you mean?

    Brent -- glad you got it worked out!
  9. 9/15/2009 11:18 PM | # re: Compiling pixel shaders for Silverlight
    Hi Tim -

    To clarify: I'd like to know the RGBA value of each rendered pixel *after* the pixel shader has been applied.

    With regards to the application, think of computational photography/image processing. See for example the following post by René Schulte citing the comparative speed of the pixel shader for image generation/processing:

    kodierer.blogspot.com/.../...-writeablebitmap.html

    I believe they're wrong in claiming that the custom shader runs on the GPU in Silverlight 3. (Unless they DO??) However, even the DX9/OpenGL software-rendering pipeline is still much faster than JITed C# (and I assume actual GPU acceleration is on the way anyway).

    If I could access the shaded data, I could save the computed result or use that as the source of my next computation (in a reduction, for example), reminiscent of the "old" GPGPU days...before it was rebadged "GPU Computing" and you had to use OpenGL/DX for computing with the GPU. If I could render to an "off-screen" buffer that would be cool too...
  10. 9/16/2009 1:34 AM | # re: Compiling pixel shaders for Silverlight
    Sorry - I totally misquoted the article. They explicitly say that the shaders are run on the CPU. Also, looks like they're SSE-optimized and multithreaded - very fast compared to the same computations using C#.
  11. 9/22/2009 3:14 PM | # re: Compiling pixel shaders for Silverlight
    Any thoughts?
  12. 11/2/2009 10:50 PM | # re: Compiling pixel shaders for Silverlight
    I'm beginning to think mentioning GPU computing kills the party...had trouble here, too:

    channel9.msdn.com/.../?CommentID=480398
  13. 12/2/2009 6:15 AM | # re: Compiling pixel shaders for Silverlight
    Hi Tim your posts are really helpful to me. I am learning it myself

 
Please add 5 and 2 and type the answer here:
First time here? You are looking at the most recent posts. You may also want to check out older archives. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS or email. Thank you for visiting! (hide this)