14

I must have misunderstood something with shaders:

I thought that as you can attach multiple shaders to one program, you'd be able to simply attach more than one fragment shader, as an example: A crate texture rendered with a color modulation and refraction.

But apparently this is not the case, as you can have only one main function per program.

  • How can I work around the main function limit and allow for any dynamic combination of multiple fragment shaders which are in the same program and called after each other?
Nightshade
  • 141
  • 1
  • 1
  • 3

4 Answers4

25

You can have a set of entry points pre-defined. Suppose you have a limited number of effects (diffuse, specular, environment, etc). None of them is applied at most once, so you just need to create a managing shader like that one:

void apply_diffuse();
void apply_specular();
void apply_environment();

void main(){ ...
     apply_diffuse();
     apply_specular();
     apply_environment();
...}

Then, when it's time to link the shader program you attach the corresponding implementations as separate GLSL objects. Some implementations may be dummies if you don't want the effect. This approach doesn't require source text parsing and has next to no performance penalty.

kvark
  • 5,291
  • 2
  • 24
  • 33
  • 1
    You just didn't answered the main question - how to do it? How can I attach separate GLSL objects, what are they? Are they shaders? But I can't have more than one fragment shader in one program. – Simon Feb 04 '14 at 17:38
  • 5
    @Simon A GLSL program links from an arbitrary number of [GLSL objects](https://www.opengl.org/wiki/GLSL_Object). It works in the same way C programs are linked: you can have many fragment shaders, but only one has to have a `main()` function. – kvark Feb 05 '14 at 03:50
11

You can't. This is known as the combinatoric explosion of shaders. Either you use massive shaders- called the Übershader approach- or I believe you can achieve it by messing with the preprocessor and generating the shaders you need on the fly.

Newer versions of GLSL should support virtual functions, which allows you to modularly build them as you would in CPU code- HLSL5 does.

Sergey K.
  • 24,894
  • 13
  • 106
  • 174
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    Damn, why didn't they build this into GLSL from the start - this seems extremely important.. – Nightshade Aug 29 '11 at 21:06
  • 3
    @Nightshade: Because it's extremely slow, and it's only recently become necessary since more and more shading techniques have come into being. – Puppy Aug 29 '11 at 21:07
  • 1
    It's not terribly slow, at least not in use. It does take a bit longer to compile, and has been supported through all versions of HLSL and Cg. GLSL is simply lacking quite a few features. – ssube Aug 30 '11 at 05:55
  • 2
    @peachykeen: Funny, because the MSDN site clearly lists dynamic linking as a new feature of HLSL5. – Puppy Aug 30 '11 at 13:08
2

The problem is the terms you are using.

Let me make a similitude:

  • An executable is composed by linked objects, objects are compiled from source.
  • A shader program is composed by linked shader objects, shader objects are compiled from source.

As you can see, a shader program is the executable. It links multiple shader objects. Each shader object is compiled from a source. As for usual executable, there is only one main entry point, which is defined by only one shader object. Just like compiling with any compilation tool-chain.

The solution is the good balance between shader objects combinations and the number of shader programs. Of course it would be beautyful to have only one shader program for rendering, but that's pretending too much: try to factor the shader functionalities, then compiled separately those functionalities and link as needed.

And you must have a look on OpenGL Registry, I think you may find something interesting in the extension list.

Luca
  • 11,646
  • 11
  • 70
  • 125
-2

You can have multiple programs in a shader, but not the other way around.

To make multiple combinations, the easiest way is to store each major chunk as a fragment with a named entry point, then include them from another program or combine them at runtime into a single program, calling them in the order you need. That can get messy though, when handling input and outputs.

You can use multiple passes, with different effects and programs in each pass. That has some additional overhead, but can be easier to set up.

ssube
  • 47,010
  • 7
  • 103
  • 140
  • Programs in a shader?! Since when can shader objects *contain* program objects? – Nightshade Aug 29 '11 at 21:05
  • The hierarchy of a shader is shader, technique, pass, program. Each pass contains vertex, fragment, geometry, and/or tessellation programs, and is contained by a technique (set of sequential passes creating a particular effect), which is contained by a shader. – ssube Aug 29 '11 at 21:06
  • 10
    @peachykeen Are you sure you're talking about simple GLSL shaders and not some fx format or some mind abstraction of programmable shading? – Christian Rau Aug 29 '11 at 21:12