Explicit multisample and shader management

I have been looking at how to use multisample color attachments for shading, and there is one issue that comes up all the time. Shaders for regular and multisample settings usually end up almost equal, with just a few minor syntax differences. But, therefore, are very hard to keep in sync while writing the code.

Is there a way to write them in a more universal way? Differences are really just a few keywords, and number of subsamples used.

Can you bind GL_TEXTURE_2D to sampler2DMS, or do a texelFetch from GL_TEXTURE_2D from subsample 0? Or is there maybe some other trick I don’t know?

It is for precisely reasons like this that the GLSL compilation functions take multiple strings.

Simply extract out the “minor syntax differences” into a separate string (ie: file), which has an expected interface that the rest of your shader uses. The two variations of this shader string will expose the same interface, but implement it differently.

I was really hoping to avoid this approach.

It seems much easier to write/edit shaders in Notepad if they are a single string. Errors match the lines, it’s a simple update of a file for modifications. But as soon as they start to get build in a custom way, things seem to get unnecessary complex.

While singlesample shader ofter is just the same shader as multisample one with some sampler2DMS replaced to sampler2D and num_samples set to 1. So just binding GL_TEXTURE_2D to sampler2DMS and setting uniform of sample count to 1 would be perfect. No syncing of files, no markers, no shader cutting…

Are there any good tutorials on how to structure shaders for more abstract interfaces, to be able to use the text fragment approach more effectively?

[QUOTE=ShaderDev;1264363]I have been looking at how to use multisample color attachments for shading, and there is one issue that comes up all the time. Shaders for regular and multisample settings usually end up almost equal, with just a few minor syntax differences. But, therefore, are very hard to keep in sync while writing the code.

Is there a way to write them in a more universal way? Differences are really just a few keywords, and number of subsamples used.
[/QUOTE]

I would agree with your goal to keep the code for reading from 1xAA and MSAA textures in the same ubershader. It’s actually pretty simple.

Can you bind GL_TEXTURE_2D to sampler2DMS, or do a texelFetch from GL_TEXTURE_2D from subsample 0? Or is there maybe some other trick I don’t know?

No to the former (AFAIK), but yes to the latter (which is what I did)! There’s a minor subtlety to that though When you use texelFetch from a multisample 2D texture, the 3rd argument is the sample index within a texel, whereas when you are sampling from a normal 1x 2D texture, the 3rd arg is the MIP level. If in the 2D case you’re always sampling from the base MIP level, then you just pass 0 in for this arg and can “pretend” its a sample index of 0 (which it’s not).

So for instance, what you want is for your ubershader generator to preprend a #define NUM_SAMPLES value to your shader code, which will be used to driver the code generation. Then, just code your fragment shader something like this:


#define NUM_SAMPLES 4        /* This line is prepended by your ubershader generator code */

#if NUM_SAMPLES > 1
  uniform sampler2DMS tex;
#else
  uniform sampler2D tex;
#endif

void main()
{
  ...
  for ( i = 0; i < NUM_SAMPLES; i++ )
  {
  // NOTE: If tex is 2D (#samples=1), i is a MIP level rather than a sample index, but 0 is fine in this case.
    color = texelFetch( tex, ivec2( gl_FragCoord.xy ), i );
    // Integrate color sample value here
  }
}