Compiling and using shaders

Started by
22 comments, last by InfoGeek 9 years, 7 months ago


Yeah it will end up being compiled to the same code so it could just be copied instead of included

no mechanism to have shared declaractions across shaders?

Advertisement

What did you have in mind? If you were to declare a cbuffer or something in a header and then include it in multiple shaders, while the shader compiler will ultimately copy the declaration to both shaders, the actual resource can be shared from C++ like this:


context->PSSetConstantBuffers( 0, 1, &buffer );
context->PSSetShader( shader1, NULL, 0 );
... do some drawing ...
context->PSSetShader( shader2, NULL, 0 );
... do some more drawing ...

Here the buffer is bound to slot 0, which will apply to any activated pixel shader until PSSetConstantBuffers is called again. The result would be the same if you called PSSetConstantBuffer again with the same buffer before using shader2, but it is better to try to reduce API calls by preventing redundant state changes. Setting up a system to handle checking for redundancies and only calling API functions when necessary is ideal.

thank you megadan :) i guess common declarations should be ignored then because as you say the actual resources are not duplicated.

sorry for dragging this thread for a bit.

Defines can be set with the pDefines parameter of D3DCompileFromFile. See http://msdn.microsoft.com/en-us/library/windows/desktop/hh968107(v=vs.85).aspx for an example.

there was no preprocessor/include related code in example .hlsl files, so if i go the runtime compiling of shader way i would have to pass a:


D3D_SHADER_MACRO Shader_Macros[1] = { "FONT_COMMON", "1"  };

having something like:

font.hlsli


#if DEFINED(FONT_COMMON)

struct commonStruct
{
   int whatever;
   float whatever2;
}

#endif

to every compiling call of a shader that includes that common include like so:

font_ps.hlsl


#include "font.hlsli"

float4 PS(VS_OUTPUT input) : SV_TARGET
{
   // do pixel shader stuff...
}

Call (Second parameter Shader_Macros):


D3DCompileFromFile(L"font_ps.hlsl", Shader_Macros, 0, "PS", "ps_5_0", 0, 0, &PS_Buffer, 0);

right?

because


#ifndef COMMON_H
#define COMMON_H

struct commonStruct
{
   //... whatever ....
}

#endif

would not make sense because it's run-time right?

If so seems a bit messy.


because

#ifndef COMMON_H
#define COMMON_H

struct commonStruct
{
//... whatever ....
}

#endif

would not make sense because it's run-time right?

Two sides of the same coin. If the above code appears in a file (either in the file or #include'd), you could define COMMON_H to exclude the code blink.png , which is counter-intuitive. (Not sure what you mean by "run-time.") FYI, though that's often used in header files to prevent (well.. attempt to avoid) multiple defines, it's still just a ifndef/endif construct.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


Two sides of the same coin. If the above code appears in a file (either in the file or #include'd), you could define COMMON_H to exclude the code , which is counter-intuitive. (Not sure what you mean by "run-time.") FYI, though that's often used in header files to prevent (well.. attempt to avoid) multiple defines, it's still just a ifndef/endif construct.

i have no idea what you tried to say here. what's the point of "#if DEFINED(FONT_COMMON) //.... #endif" then?

run-time as in program run-time compilation of shaders instead of program compile time.


i have no idea what you tried to say here. what's the point of "#if DEFINED(FONT_COMMON) //.... #endif" then?

Just observing that #ifndef COMMON_H is the same in kind as an #ifdef FONT_COMMON. Interpretation takes place at shader compile time, whenever that occurs.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


Just observing that #ifndef COMMON_H is the same in kind as an #ifdef FONT_COMMON.

oh, okay, thanks for the input.

Still wondering on the answers to my previous post.

so if i go the runtime compiling of shader way i would have to pass a ... to every compiling call of a shader that includes that common include like so:


Generally, this is correct. Each shader will have its own set of defines. The same is true for C++. The compiler passes some set of defines to each individual file as it gets compiled.

In C++,#ifndef/#define is used to prevent a cpp file from including two headers that both include the same header which would lead to something being defined multiple times in the cpp file. The same is true for shaders. So if your shader header is being included in other headers that are then being included in your shader, it's a good idea to put an #ifndef/#define to prevent multiple declarations in the same file. If you are just including the header file directly in your shader, then it's not totally necessary, although it might still be good practice.

As to which method you described you should use, it depends on what you want to accomplish. If you want to prevent things from being multiply defined, use #ifndef/#define. If you want to conditionally use one struct or another struct, or one block of code or another block of code, use the #ifdef with the define passed to the compile function.

One usage example for passing a define to the compile function would be to use a different vertex layout struct for passing into the vertex shader. You can define two structs, say one with normals and the other without normals and use an #ifdef to control which is used. Then compile the shader twice, one with the value defined, and the other without. Now you have two shader objects, one that can handle vertex inputs with normals, and one without. This allows you to write one shader that you can use in multiple ways with different types of geometry.

thanks for the explanation again megadan, i knew some of it but it helps to be reassured.


If you want to prevent things from being multiply defined, use #ifndef/#define.

i want to follow your suggestion to include common header in shaders, but if i use #ifndef/#define at runtime how will it even work?

i mean at program compile time(as you said, i think...) the compiler keeps track of the #define so the #ifndef/#define method works and duplicates are excluded. if it is program runtime call to compile would it always include all files anyway because it has no way of tracking the #define ?

This topic is closed to new replies.

Advertisement