Registering shaders with shader system

Started by
14 comments, last by rick_appleton 19 years, 10 months ago
I''m trying to get the shaders/material system working. I''m wondering how you get the shaders registered with the ''shader-repository''. If you do some stuff using static members or so, then the shaders will be registered before the rendering system is up, so you can''t do anything with them yet. You''d have to store them in a list before you can do anything with them. I''m not sure how to do it differently. I''m running into some troubles that I can''t make static functions virtual. Any ideas?
Advertisement
Personally, I just have my resource manager (which manages all game assets; textures, vertex buffers, etc.) handle an array of these:

struct VShaderInfo{    String FileName;    DWORD  RenderFlags;    LPDIRECT3DVERTEXSHADER9 Shader;    LPDIRECT3DVERTEXDECLARATION9 VDecl;     int    RefCount;  };


"VShaderInfo" has a counterpart "PShaderInfo", both of which are members of a "Material" class.

Each object calls the resource manager''s "LoadMaterial()" function, which in turn calls "LoadPixelShader()" and "LoadVertexShader()", and gets a handle (just an unsigned integer index into an array) to these shaders. I compare the request to load a shader to the file names of the previously loaded shaders, and just incriment the RefCount if it''s already been loaded.

Now, when it comes to constants for the vertex shaders, I have all of my shaders allowed a set of constants that all shaders have duplicated. The first few are the obvious ones that most shaders will need (Transforms and the like). I also send the current elapsed time, and a small set of "miscellaneous" float4''s that each shader can optionally use (the "Material" dictates which ones are used, and which in-game variables correspond to said values).

It seems to work fairly well. I''m not really sure if things would be more efficient if I didn''t use ALL the constants for every shader, but if there is a performance hit, it''s negligable.

---------------------------Hello, and Welcome to some arbitrary temporal location in the space-time continuum.

I tend not to roll my own reference counting system, but to use Boost Shared Pointers instead.

Check out the boost library...

http://www.boost.org

Hope this helps.

I would probably store a std::map mapping from filename to shader pointer.

When someone goes to load a shader, try to fetch it from the map first. If you can''t, load it, add it to the map, then return it to the user. Easy!

Why you shouldn''t use iostream.h - ever! | A Good free online C++ book
I might be missing a point but I tought he was asking about registering shaders before resolving dependencies (selecting best shaders for current HW). I have 2 ways of handling this (but I use only one for now). Effect manager has function to register shader via templated function (where template parameter is the actual shader class) or via pointer to class and then effect manager duplicates shader (overloaded clone function) and inserts it into "repository". I was also thinking and experimenting with static functions but ended in a few dead ends.

You should never let your fears become the boundaries of your dreams.
You should never let your fears become the boundaries of your dreams.
Depends on how your shaders are stored to begin with. Also a little about how your shader registry works.
In my engine, shaders are derived objects, allocated in external libs and exposed to the engine one by one. Each shader has a setup function and some other that are run when after the display has started up and the shader system walks through all shaders.
So, generally for me:

- Define all shaders as classes and allocate them in the lib (dev-time)
- After the display has started up, the shader system loads all shader libs and retrieves shaders (run-time)
- Check support for every shader, add valid shaders to a big list and check against shader definition elements (a little thing I got)
Thanks everyone for the answer. Sorry for not being clear enough in the question.

I did indeed mean what Darkwing mentioned. I have shaders (not necessarily vertex or fragment) that define how a material looks. These are implemented as derived from a base shader class. The base class provides some common funcionality.

I think the way coelurus described best matches my expectations. In my implementation each and every renderable object has its own instance of a specific shader class. It requests this from the repository on creation (currently using factory pattern).

The problem I was having was how to create a new shader object in the repository when asked for it. I currently have a static CreateShader function in each shader class, and I pass apointer to that to the repository when registering a shader. The problem however is that I can not enforce writers of new shader-classes to have this function, since virtual and static don''t go together.

I''ve been thinking if there might be a smart way to handle this using a copy constructor or something, but I''m not sure.

_DarkWing_: could you maybe explain the part about the duplicating of the shaders through the overloaded clone function a bit more? And how do objects get a shader from your ''repository''?
quote:Original post by rick_appleton
_DarkWing_: could you maybe explain the part about the duplicating of the shaders through the overloaded clone function a bit more? And how do objects get a shader from your ''repository''?

Shader base class has pure virtual Clone() method that returns pointer to base shader. Then each shader overrides it with simmilar method that returns the actual shader class and sets some shader variables if needed.

class MyShader : public IShader {...   IShader* Clone() {       MyShader *shader = new MyShader();       shader->var = var;       ...       return shader;   }...} 


I register most shaders inside a call to effect manager''s method "RegisterStandardShaders()" that registers all shaders that are implemented internal (in exe). Shaders that are implemented in dll register themselfs in dll entry point. (But for a while now I haven''t used dll part and I don''t even know if it compiles becouse I made some huge changes in global design)

Objects (namely Material Manager) gets shaders from effect manager via "IShader* GetShader( int effectID )" method. This once again uses shaders clone method.
IShader* GetShader( int effectID ) {    if ( effect[ effectID ].hasValidShader ) {         return effect[ effectID ].shader->Clone();    } else {         throw some nasty error or select default "error" shader    }} 



Personaly I would like to hear how Yann or jamessharpe (I hope i wrote this right) do this.

You should never let your fears become the boundaries of your dreams.
You should never let your fears become the boundaries of your dreams.
Ok, that's sort of what I was expecting. I was trying to find a way around having copies of the each and every shader hanging around.

edit: And I agree, I hope one (or both) of them will pop in here.

[edited by - rick_appleton on June 7, 2004 10:41:41 AM]
quote:Original post by rick_appleton
I was trying to find a way around having copies of the each and every shader hanging around.

I think it might be possible with *alot* of template magic, but it is up to you to judge if its worth the effort. Although waste of memory with this method is minimal, I hope some C++ guru will come up with more elegant solution.

You should never let your fears become the boundaries of your dreams.
You should never let your fears become the boundaries of your dreams.
quote:Original post by _DarkWIng_

Personaly I would like to hear how Yann or jamessharpe (I hope i wrote this right) do this.



The way I do it is to not allow specific access to the shaders outside the rendercore. All shaders are retrieved via the shadermanager. It is implicit in the design that there is only ever one instance of the shader, although this isn''t enforced and I see no reason to do so, and hence I don''t have any ''clone'' function.(Btw _Darkwing_ why don''t you use the copy constructor for setting the variables? simply return new Shader(*this); )

Where do I register the shaders? I register them as the render context is created, similar to Darkwing''s RegisterStandardShaders(). My dll implementation is currently in a state of flux, I''m currently porting the code to Linux, and as a result has required me to have a bit of a rethink with the dll design, it wasn''t abstracted properly(or at least the search code for the dll files) Anyway the way I do it is simply have a function available RegisterShaders(ShaderManager *) which then creates and registers the appropriate shaders.

James

This topic is closed to new replies.

Advertisement