Some StitchUp updates
The short version
There is a new build of StitchUp available here.
It includes these new features: * The parser supports initial values for parameters. * The parser supports C-style single line comments. * The build output window in Visual Studio now shows a clickable message for the generated effect
The long version
After my last post introducing StitchUp, I received some feedback, including a very detailed comment from "Alejandro" (sorry Alejandro, I'm not implying I'm on first name terms with you, I just don't know your surname). I started to reply to his comment, but it got quite big, so I thought I'd write a new post, which will allow me to wax more lyrical about some new features. I also think some of his questions might be interesting for a wider audience.
So, here are his questions, and my responses:
In the [params] body, how can I set a starting default value? like: [params] float4 color : DIFFUSE_COLOR; // = { 1,1,1,1}; ?
It wasn't possible before, but it is now. I've modified the parser to include support for initial values. So the following declarations are now possible - note that this is only valid within the [params] block, since they are the only variable declarations that initial values make sense on.
[params]
float3 lightDir : LIGHT_DIRECTION = { 1.0f, -1, 1 };
float3 lightDir = { 1.0f, -1, 1 };
float3 lightDir = float3(1.0f, -1, 1);
Next question:
... the BasicMaterial fragment doesn't import anything but has a [vertex] attribute and interpolator. Is there some magic wand going around behind the scenes? Like: "No one output-ed an uv and you need it, so I'll just give to you"?.
Yes, that is exactly what is happening. The code generator follows these rules:
- If the fragment includes a vertex shader, then use it - don't auto-generate one. You might have values in the
[interpolators]block that you want to pass to the pixel shader, but that is not going to happen automatically. You need to use theoutputmeta-function, which is used byPositionNormalTexture.fragmentin the demo project. - If the fragment doesn't include a vertex shader, then auto-generate one. The code generator creates pass-through statements for all values in the
[interpolators]block. For BasicMaterial, the auto-generated vertex shader looks like this:
// -------- vertex shader basic_material2 -------- void basic_material2_vs(basic_material2_VERTEXINPUT input, inout VERTEXOUTPUT output) { output.basic_material2.uv = input.uv; }
Next question:
Is it still possible to #include an .fxh with basic functions and methods? I tried but failed big time. Or the correct practice would be to think about "Helper Fragments" and you would be actually "importing the methods"? (for things like random, poisson things, etc).
Yes, this is supported, in two ways.
- You can create a fragment with only a
[headercode]block. SeeDirectionalLight.fragmentin the demo project for an example. I think this is the most elegant solution. - You can use
#includewithin an__hlsl__block, but because of the way I'm callingEffectProcessorwith a dynamically generated effect, you'll need to use absolute path names (i.e.C:\...\MyInclude.fxh).
Next question:
Is there a way to see the stitched .fx file (ouput somewhere in some folder). I only see it when there is an error (usually name mismatch). Visual studio keeps it in a temporal folder.
The output is always called StitchedEffect.fx, and it's always saved in your temp folder. You're right that Visual Studio only shows you a clickable error message if there's an error. I've actually asked on the App Hub forums how to do this for informational messages. In the meantime, I have added a message to the build output log, which you can double-click on to open the stitched effect file. The message looks like this:
C:\Users\Tim Jones\AppData\Local\Temp\StitchedEffect.fx : Stitched effect generated (double-click this message to view).
Next question:
When assigning Visual C++ as the .fragment text editor (to get a little bit of syntax highlighting) commenting a line outside of the hlsl body (via ctrl+e, c) will always crash Visual Studio. (Is there a way to assign NShader as the syntax highlighter for the .fragment? that would be awesome)
The first little issue is that the StitchUp parser didn't allow for comments. I've implemented that now, so you can use C-style single-line comments in your .fragment files:
float3 lightDir : LIGHT_DIRECTION = { 1.0f, -1, 1 }; // This is a comment.
//float3 lightDir : LIGHT_DIRECTION = { 1.0f, -1, 1 };
I hadn't heard of NShader before - that's a nice project. The only way I could see to add support for .fragment files was to change the original source code. Since the developers of NShader are unlikely to be interested in supporting StitchUp-specific extensions, I have created a fork of NShader. You can download the StitchUp-specific VSIX file. So far I have only added support for the .fragment extension, but it would be nice to add support for StitchUp keywords, such as export, import and output. Oh, and you probably don't want to install it at the same time as the official NShader package - in any case, Visual Studio probably won't let you, because I haven't changed of the package GUIDs.
After installing this custom version of NShader, your .fragment files should look like this:

Hope this helps - as always, please post thoughts, feedback, etc. below.
13 comments
Nov 19, 2010
04:04
No problem at all "Tim Jones".
That was fast. Well now thats two jaw-drops in a row.
NShader is working as expected. I was looking through the fork source code, perhaps its only a matter of creating a new map file with the added keywords, load it through the map.load method and done. I hope Alexander Mutel (NShader) manages to pull off autocompletion. The round trip would be complete!.
I see that you build all .fragment files and add them to the content folder along with the final stitched file. Is there a reason behind this? like custom stitching at runtime depending on machine specs?. On general purpose I will likely be interested in the final file only. however they are tiny files and don't pose a problem at all. Just curious.
Clickable file: perhaps what would you want is to copy the resulting .fx file to the same folder path the .stitchedeffect sits (not included in the content project, or included with the compile flag disabled). That way it has easy access to open it and watch it, and perhaps see it through an easy disassembler to see how the final driver compiles the .fx file (this way you can see how many registers, preshaders, etc are being used). Like Renaud Bédard Disassembler app http://theinstructionlimit.com/?p=34
Again, awesome work man. Code generation tools are indeed a very very powerful arsenal.
Nov 19, 2010
07:46
Hi,
Stitch up is really the kind of tool I am looking for. After tried a little bit, I come up with a feedback:
The only parameter type supported are float(n), bool and matrix, is it possible to support floatNxN and arrays. We don't always need float4x4 but sometime float3x3 or float4x3 as well. And arrays are useful for vertex skinning.
Nov 19, 2010
09:19
And another one that might be a Bug:
Global variables can't be chained, say I had a Position.fragment that exports a variable:
fragment Position;
[vertex] float4 Position : POSITION;
[vs 20] __hlsl_ void main(INPUT input, inout OUTPUT output) { export(float4, InputPosition, input.Position); } hlsl
and I had a PositionTransform.fragment that did some manipulations but doesn't output the result, instead it export the result to be used by later passes:
fragment PositionTransform;
[parameters] matrix World : WORLD; matrix ViewProjection : VIEWPROJECTION;
[vs 20] __hlsl_ void main(INPUT input, inout OUTPUT output) { float4 position; import(InputPosition, position = InputPosition);
} hlsl
But the generated .fx code is:
void PositionTransform2_vs(PositionTransform2_VERTEXINPUT input, inout VERTEXOUTPUT output) { float4 position; // metafunction: import(InputPosition, position = InputPosition); position = Position0_export_InputPosition; position = PositionTransform2_export_InputPosition;
}
And this line is where the bug is:
position = PositionTransform2_export_InputPosition;
Hope you can fix it :-)
Nov 19, 2010
10:45
And the [vs 2_0] & [ps 2_0] really doesn't help much, since even if a single fragment support vs 2_0, the final composed vertex shader might not because of limited instruction slots. Perhaps you can remove these attributes and try to compile againest 2.0, 3.0 and maybe 4.0 to find the minimum profile required by the shader.
Thanks.
Nov 20, 2010
16:28
Hey Tim - amazing tool! I can't thank you enough for not only making this but releasing the code. I'v been playing with it for the last 2 days and here are some comments:
like other posted, there needs to be at least support for float3x3 and float 4x3. And the chained exports is a great idea.
texture states is a big requirement for things like shadowmaps and heightmaps etc. I modified your code to allow an initial value on texture variable declarations. The initial value becomes the sampler state such as:
texture2D shadowmap : shadowmap = { MinFilter = Point; MagFilter = Point; }
turns into
texture2D BasicShader0_shadowmap : shadowmap ; sampler BasicShader0_shadowmap _sampler = sampler_state { Texture =; MinFilter=Linear;MagFilter=Linear;};
I also added support for Texture3D and TextureCube
My render engine relies on Pass annotations to setup the GraphicsDevice. It would be great to expand .stitchedeffect to contain technique/pass definitions so I can add annotations. This would also allow multiple techniques. Something like:
technique A { pass A { fragments...
} }; technique B { pass A { fragments...
} };
And some nitpicky comments:
Nov 20, 2010
16:31
There is a cut and paste error on the texture sampler code where Linear should be Point but you get the idea I hope.
Nov 21, 2010
16:41
Thanks for the feedback - it's great to hear that this might be useful to somebody (and maybe even somebodies).
Yufei andMadoxLabsI have added support for matrix data types and arrays.
`Yufei - The chained export / import bug is an interesting one. There certainly was a bug - "import(InputPosition, position = InputPosition);" shouldn't have included the export from later in the fragment - this is fixed. However, as you've written it, the third fragment (which you didn't include) which imports the second export won't work, and it wouldn't have worked with Shawn's original system either. This is because a call to "import" will pick up ALL previous exports matching that name, not only the previous one. So you'd end up importing the exports from both Position.fragment and PositionTransform.fragment. That behaviour is both powerful and desired, but obviously doesn't help you for what you're trying to do. Will simply using a different name work?
`MadoxLabs - I have logged an issue for supporting sampler states, but I'd like to get some more feedback on the syntax before implementing it. I'm not totally comfortable with using a sampler_state definition to "initialize" a texture variable, but admittedly I can't think of a better solution.
I have started a discussion around the best way to implement techniques - please vote and comment with your thoughts.
I have added support for Texture1D, Texture3D and TextureCube.
I have added support for MRTs.
I have tried to explain my rationale behind the hlsl delimiters.
I have run out of "I have's" ;-)
Nov 21, 2010
17:12
@MadoxLabs - I meant to say, having read your article on your grand unified model renderer, I should point out that StitchUp doesn't (yet) support annotation syntax. If you'd like it to, please log an issue - annotations would certainly be useful to have.
Nov 21, 2010
18:06
Haha, you found my post, eh? I didn't link it here directly because I felt like it isn't really ready for primetime yet. However, Stitchup doesn't need to support annotations more than passing them through to the final .fx file.
Initializing the texture that way was just a quick hack using the new feature you provided, but I think doing something more 'proper' would only add verbosity and nothing else. Maybe thats good though.
Do you mind me logging issues for other things I'd like you to check out?
Nov 21, 2010
18:15
@Madox - Actually, since StitchUp's parser is response for anything outside hlsl blocks, and since it currently doesn't know what annotations are, I would need to do some work to add support for them (similar to what I did for supporting arrays and initial values).
Yes, please do log issues - if I think they'll be useful for a majority [and if they're not too hard :)] then I'll do my best to implement them.
Nov 22, 2010
02:24
OK, I started adding issues for things I ran across and made changes for. I'm trying to only enter ones useful for a majority and not ones that are just for me (like changing ReplaceOutputCalls() to work on 'output.' instead of 'output()')
Let me know if its too much. I was just about to start making my own tool when I found yours, so I'm pretty excited.
Nov 22, 2010
09:19
Yes, "import" do pick up ALL previous exports matching that name as I saw in your code, and I just modefied the PreProcesser and make it first process imports then exports, then everything magically works in my case. This way, the imports in the current fragment is not included.
And for data types, it seems you don't have much good uses for them, why not just use a string to represent everything, there are also Half(n) and whatever odd types available in HLSL.
Nov 22, 2010
09:29
`MadoxLabs - no, not too much :) I'll take a look at them in more detail shortly.
`Yufei - I made the same change in PreProcessor, and I've committed that already. What I meant was that your third fragment must have something like this:
import(InputPosition, position = InputPosition);
which would expand to:
position = Position0_export_InputPosition; position = PositionTransform2_export_InputPosition;
... which I guess works, but only because the second assignment overwrites the first one. If you were doing another operation (i.e. += or *) then it wouldn't do what you expect.
True, I could remove the data type parsing, but I quite like having it in there - it means I can pick up on syntax errors early in the process, and show nice error messages that link to the correct line and column in the .fragment file. Yes, it does mean I need to do some more work to support all HLSL data types. Please do log issues for data types that you'd like to see added - eventually StitchUp should support all HLSL data types. The only reason it doesn't right now is because I'm lazy ;-)
Make a comment
Sorry, commenting has been temporary disabled because of spam. If you have any questions, you can email me, and you can also find me on Twitter.