(Note that some of these ideas have been previously proposed by others but were never implemented)
RTSS - Real time shader system
SRS - Sub-render state
cleaner code features
- Remove the internalOrder (third) parameter from the FunctionInvocation constructor, and make the groupOrder (second) parameter optional.
From what I've seen the code for creating FunctionInvocation in SRSs is almost always the same. There are 2 parameters defined in every SRS one is used to carry the groupOrder the other the internalOrder. The value groupOrder parameter is almost never changed, while the internalOrder is constantly incremented for every creation of a FunctionInvocation. This is duplicate code which can be removed.
Both values can be replaced by parameters defined in the RTShader::Function class. The internalOrder equivalent parameter will need to be updated once at the beginning of the call to addFunctionInvocations. The internalOrder equivalent parameter will be assigned and incremeted every time a FunctionInvocation is added to a function.
The groupOrder parameter in the FunctionInvocation constructor should be kept as optional parameter to provide a way to overide the groupOrder parameter in the RTShader::Function class. This is both for easier converting of older code and to provide an overriding value for unique functions. - All commonly used functions such as assign, add, transform should have helper function to write them.
Currently to write a common function into a shader takes several lines of code. This should be replaced by single line of code using "helper" functions. For instance, a function for creating assignment or multiplication can have the prototypes:FunctionArg (short for function argument) will be a new class which will describe either a parameter, a parameter with a mask, a const value (e.g. float, Vector3, etc...) or a GpuProgramParameters enum to describe a uniform parameter.Code: Select all
void ShaderFunctionUtil::addFunctionAssign(Program* prg, FunctionArg assignedValue, FunctionArg target); void ShaderFunctionUtil::addFunctionTransform(Program* prg, FunctionArg multiplicand, FunctionArg multiplier, FunctionArg target);
So that this code:
Code: Select all
UniformParameterPtr wvpMatrix = vsProgram->resolveAutoParameterInt(GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX, 0); ... vsProgram->addDependency(FFP_LIB_TRANSFORM); ... FunctionInvocation* transformFunc = OGRE_NEW FunctionInvocation(FFP_FUNC_TRANSFORM, FFP_VS_TRANSFORM, 0); transformFunc->pushOperand(wvpMatrix, Operand::OPS_IN); transformFunc->pushOperand(positionIn, Operand::OPS_IN); transformFunc->pushOperand(positionOut, Operand::OPS_OUT); vsEntry->addAtomInstance(transformFunc);
will be condenced to this code:
Code: Select all
ShaderFunctionUtil::addFunctionTransform(vsProgram, FunctionArg(GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX), FunctionArg(positionIn), FunctionArg(positionOut));
Easier integration and cleaner code features
- Remove the concepts of input / local / output parameters from SRS building. (Note: I'm not 100% sure about the following idea)
Currently when a user wants to use a specific type of non-uniform shader parameter (position, normal, texcoord, etc...), he has to define between 1 and 3 parameters to hold the value of that parameter.- An input parameter to recive the value of the parameter from the vertex buffer / vertex shader.
- An optional local parameter to contain and manipulate the value of the parameter.
- An output value to send the parameter to the pixel shader or color output.
This can be replaced with the following:- The 3 parameter types (input, local and output) should be combined into a new single parameter ("combined parameter"). More akin in concept to the local parameter then to the other input or output.
- When creating a combined parameter the user will need to specify how the parameter is initialized. Whether through a const value or through a value from a vertex buffer. This will tell the system whether an input parameter is needed as well.
- For pixel shader parameters the user will be able to define vertex shader parameters from which the parameter will be initialized. This should automaticly create the input and output parameters for sending the value from the vertex shader and reciveing it in the pixel shader.
- The first few lines of every shader should be resereved for initializing the values of these new types of parameter.
- The last few lines of every shader should be reserved for assigning values from these type of parameters to shader output parameters.
- The way that the RTSS is designed to work is that each SRS component is ment to do a small section of the overall computations required in the shader. Where each component is a "black box" unaware of what other SRS components do.
This unfortunatlly does not produce the best results. Consider the transform SRS and the lighting SRS. The per pixel lighting SRS requires the vertex normal in camera space. Because lighting SRS is not aware the transform SRS it has to attempt to convert the normal from object to view space by itself. it takes the normal in object space and converts it through the world-matrix parameter. However some transform (hardware skinning) SRSs components don't use the world-matrix. They use other parameters. So to overcome the fact that the pixel shader is not aware of them they have to calculate the normal in world space then convert it back to object space, so that the lighting SRS can pick it up from there. This is awkward inefficient code.
Before all the SRSs are called serially to produce their shader code (resolveParameters() and createCpuSubPrograms()), There needs to be a pre-stage where the SRSs declare what they need or what they expect. That way in the previous example the lighting stage should declare that it requires the normal in view space. And the transform SRS can create it.
If I combine this idea with the previously listed idea I come up with this: When creating a combined parameter, instead of having to specify the initialization value, the programmer will be able to define the parameter as "waiting for initialization code". These type of parameters will be created at the above described decleration stage. When the next stage of shader code production arraives, SRSs such as the transform SRS will be able to tell whether there is a value the need to provide and do so if neccessary.
- Texture SRS should support using parameters with greater size than the texture requires.
- Add a tag ("texture_use") that will inform the texture SRS that it does not require to use a texture. Extend this tag to SRSs that use textures such as normal map lighting.
- Add tags that add the ability block basic SRSs, such as transform, texture, color, light and fog.
- Add ability to tell the system that when an SRS should not be used, the next SRS for the same group order should be checked.
- Better naming conventions for parameters inside shaders (for easier debugging).
Far future developments
- support geometric shaders