Compute shaders

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 267
Joined: Wed Apr 23, 2014 3:49 pm
Location: Bologna, Italy
x 75

Compute shaders

Post by TaaTT4 »

Hi,

I've begun to play with compute shaders and I have two quick questions.
What's the purpouse of inform_shader_of_texture_data_change? I've seen that in every *.material.json file that declares a compute shader is set to true. But reading the HlmsComputeJob::setInformHlmsOfTextureData documentation it seems that is it should be left as it is to false (unless you know what you're doing).
Correct me if I'm wrong, but at the moment there's no way to set preprocessor definitions of a compute shader, right? Would it be hard to add this feature? I'm asking this because I have some 3rd party compute shaders that enable/disable features by defines. I'd like to keep them as they are to simplify the merge/update process in the future.

Senior programmer at 505 Games; former senior engine programmer at Sandbox Games
Worked on: Racecraft EsportRacecraft Coin-Op, Victory: The Age of Racing

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5511
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1379

Re: Compute shaders

Post by dark_sylinc »

There are several properties that are only set when inform_shader_of_texture_data_change is true.
These properties are in HlmsComputeJob::setTextureProperties

The most important one is probably uav0_pf_type, which is why inform_shader_of_texture_data_change is often true.

Regular textures can switch formats dynamically. e.g. you declare in HLSL:

Code: Select all

Texture<float4> myTex;
And you can later bind a texture with format PFG_RG8_UNORM and myTex.Sample().xy will return the valid values, while .zw will return 0.
Everything works.

UAVs however don't. You must declare the proper format. If you expect to bind PFG_RG8_UNORM, then you must declare:

Code: Select all

RWTexture<unorm float2> myUav;
Even the 'unorm' part is mandatory.

If you know beforehand which format you expect to bind, then you can hardcode it and leave inform_shader_of_texture_data_change as false (assuming you also don't use any of the other properties that are only defined with this setting)

But otherwise, you can use the Hlms to dynamically define the format:

Code: Select all

RWTexture3D<@insertpiece(uav0_pf_type)> outLightHigherMip0 : register(u0);
And that's why inform_shader_of_texture_data_change is often true.

If a ComputeJob keeps switching textures or uavs very often, there is a performance overhead as we must reset the texture properties, and then:
  1. We see if a shader with the exact same properties is already in the cache.
  2. If it's not, then we must generate the new shader code by running the Hlms parser.
  3. Then we see if the generated shader is already cached (because two jobs with different properties may end up producing the same output if e.g. you don't use those the key properties that changed).
    This isn't slow, but it can take its time: for example the shaders based on GaussianBlurBase_cs use a lot of @foreach, and the parser takes noticeable time (specially on Debug)
  4. If the generated output is not in the cache, we compile the HLSL/GLSL/Metal code (and that can be super slow)
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5511
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1379

Re: Compute shaders

Post by dark_sylinc »

TaaTT4 wrote: Mon Oct 14, 2019 11:47 am Correct me if I'm wrong, but at the moment there's no way to set preprocessor definitions of a compute shader, right?
We don't have that feature at the moment. You can workaround it by setting them at the start with Hlms properties:

Code: Select all

@property( MY_DEFINE )#define MY_DEFINE @value( MY_DEFINE )@end
Or via pieces from C++ code:

Code: Select all

// C++ code:
const char *definitions =
"#define PARAM_A\n
#define PARAM_B";
computeJob->setPiece( "my_custom_definitions", definitions );

// Shader code at the top:
@insertpiece( my_custom_definitions )
TaaTT4 wrote: Mon Oct 14, 2019 11:47 amWould it be hard to add this feature? I'm asking this because I have some 3rd party compute shaders that enable/disable features by defines. I'd like to keep them as they are to simplify the merge/update process in the future.
I don't think it's very hard.
The shaders already support custom definitions via:

Code: Select all

gp->setParameter( "preprocessor_defines", "..." );
that should be called in HlmsCompute::compileShader.

However since we perform very extensive and complicated multi-level caching, the easiest way to play nice with caching would be to store the definitions as a piece:

Code: Select all

HlmsComputeJob::setDefinitions( const String &definitions )
{
    this->setPiece( "__internal_definitions", definitions );
}
And then read that piece when calling gp->setParameter.
This should be easy for you to implement if you want to contribute.

Cheers
Matias