cg1_2_runtime_changes
Keywords: cg1_2_runtime_changes, NVIDIA, NVIDIA Cg Toolkit, Cg Toolkit, Shader, Shader Programming, GPU Shader Programming, GPU Program

> ## Cg 1.2 Runtime Api Additions

> Version 1.2 of the Cg runtime adds a number of new capabilities to the existing set of functionality from previous releases. These new features include functionality that make it possible to write programs that can run more efficiently on the GPU, techniques that help hide some of the inherent limitations of some Cg profiles on the GPU, and entrypoints that support new language functionality in the Cg 1.2 release.

> ## Parameter Literalization

> The 1.2 Cg runtime makes it possible to denote some of the parameters to a program as having a fixed constant value. This feature can lead to substantially more efficient programs in a number of cases. For example, a program might have a block of code that implements functionality that is only used some of the time:

>     float4 main(uniform float enableDazzle, ...) : COLOR {
>       if (enableDazzle) {
>         // do lengthy computation
>       }
>       else {
>         // do basic computation
>       }
>     }

> Some hardware profiles don't directly support branching (this includes all of the fragment program profiles supported in this release), and have to handle code like the program by effectively following both sides of the if() test. (They still compute the correct result in the end, just not very efficiently.)

> However, if the "enableDazzle" parameter is marked as a literal parameter and a value is provided for it, the compiler can generate an optimized version of the program with the knowledge of "enableDazzle"'s value, just generating GPU code for one of the two cases. This can lead to substantial performance improvments. This feature also makes it easier to write general purpose shaders with a wide variety of supported functionality, while only paying the runtime cost for the functionality provided.

> This feature is also useful for parameters with numeric values. For example, consider a shader that implements a diffuse reflection model:

>     float4 main(uniform float3 lightPos, uniform float3 lightColor,
>                 uniform float3 Kd, float3 pos : TEXCOORD0,
>                 float3 normal : TEXCOORD1) : COLOR
>     {
>         return Kd*lightColor*max(0., dot(normalize(lightPos-pos), normal));
>     }

> If the "lightColor" and "Kd" parameters are set to literals, it is possible for the compiler to compute the product "Kd * lightColor" once, rather than once each time the program executes.

> Given a parameter handle, the cgSetParameterVariability() entrypoint sets the variability of a parameter:

>         void cgSetParameterVariability(CGparameter param, CGenum vary);

> To set it to a literal parameter, the CG_LITERAL enumerant should be passed as the second parameter.

> After a parameter has set to be a literal, the following routines should be used to set the parameter's value.

>     void cgSetParameter1f(CGparameter param, float x);
>     void cgSetParameter2f(CGparameter param, float x, float y);
>     void cgSetParameter3f(CGparameter param, float x, float y, float z);
>     void cgSetParameter4f(CGparameter param, float x, float y, float z,
>                           float w);
>     void cgSetParameter1d(CGparameter param, double x);
>     void cgSetParameter2d(CGparameter param, double x, double y);
>     void cgSetParameter3d(CGparameter param, double x, double y, double z);
>     void cgSetParameter4d(CGparameter param, double x, double y, double z,
>                           double w);

>     void cgSetParameter1fv(CGparameter param, const float *v);
>     void cgSetParameter2fv(CGparameter param, const float *v);
>     void cgSetParameter3fv(CGparameter param, const float *v);
>     void cgSetParameter4fv(CGparameter param, const float *v);
>     void cgSetParameter1dv(CGparameter param, const double *v);
>     void cgSetParameter2dv(CGparameter param, const double *v);
>     void cgSetParameter3dv(CGparameter param, const double *v);
>     void cgSetParameter4dv(CGparameter param, const double *v);

>     void cgSetMatrixParameterdr(CGparameter param, const double *matrix);
>     void cgSetMatrixParameterfr(CGparameter param, const float *matrix);
>     void cgSetMatrixParameterdc(CGparameter param, const double *matrix);
>     void cgSetMatrixParameterfc(CGparameter param, const float *matrix);

> After a parameter has been set to be a literal, or after the value of a literal parameter has been changed, the program must be compiled and loaded into the GPU, regardless of whether it had already been compiled. This issue is discussed further in the section on program recompilation below.

> ## Array Size Specification

> The Cg 1.2 language also adds support for ``unsized array'' variables; programs can be written to take parameters that are arrays with an indeterminate size. The actual size of these arrays is then set via the Cg runtime. This feature is useful for writing general-purpose shaders with a minimal performance penalty.

> For example, consider a shader that computes shading given some number of light sources. If the information about each light source is stored in a struct LightInfo, the shader might be written as:

>     float4 main(LightInfo lights[], ...) : COLOR
>     {
>        float4 color = float4(0,0,0,1);
>        for (i = 0; i < lights.length; ++i) {
>           // add lights[i]'s contribution to color
>        }
>        return color;
>     }

> The runtime can then be used to set the length of the lights[] array (and then to initialize the values of the LightInfo structures.) As with literal parameters, the program must be recompiled and reloaded after a parameter's array size is set or changes.

> These two entrypoints set the size of an unsized array parameter referenced by the given parameter handle. To set the size of a multidimensional unsized array, all of the dimensions' sizes must be set simultaneously, by providing them all via the pointer to an array of integer values.

>     void cgSetArraySize(CGparameter param, int size);
>     void cgSetMultiDimArraySize(CGparameter param, const int *sizes);

> XXX what happens if these are called with an already-sized array?? XXX

> To get the size of an array parameter, the cgGetArraySize() entrypoint can be used.

>         int cgGetArraySize(CGparameter param, int dimension);

> ## Program Recompilation At Runtime

> The Cg 1.2 runtime environment will allow automatic and manual recompilation of programs. This functionality is useful for multiple reasons :

> Changing variability of parameters
>   Parameters may be changed from uniform variability to literal variability as described above.
> Changing value of literal parameters
>   Changing the value of a literal parameter will require recompilation since the value is used at compile time.
> Resizing parameter arrays
>   Changing the length of a parameter array may require recompilation depending on the capabilities of the profile of the program.
> Binding sub-shader parameters
>   Sub-shader parameters are structures that overload methods that need to be provided at compile time; they are described below. Binding such parameters to program parameters will require recompilation.

> Recompilation can be executed manually by the application using the runtime or automatically by the runtime.

> The entry point:

>         void cgCompileProgram(CGprogram program);

> causes the given program to be recompiled, and the function:

>         CGbool cgIsProgramCompiled(CGprogram program);

> reurns a boolean value indicating whether the current program needs recompilation.

> By default, programs are automatically compiled when cgCreateProgram() or cgCreateProgramFromFile() is called. This behavior can be controled with the entry point :

>         void cgSetAutoCompile(CGcontext ctx, CGenum flag);

> Where flag is one of the following three enumerants :

> CG_COMPILE_MANUAL
>   With this method the application is responsible for manually recompiling a program. It may check to see if a program requires recompilation with the entry point cgIsProgramCompiled(). cgCompileProgram() can then be used to force compilation.
> CG_COMPILE_IMMEDIATE
>   CG_COMPILE_IMMEDIATE will force recompilation automatically and immediately when a program enters an uncompiled state.
> CG_COMPILE_LAZY
>   This method is similar to CG_COMPILE_IMMEDIATE but will delay program recompilation until the program object code is needed. The advantage of this method is the reduction of extraneous recompilations. The disadvantage is that compile time errors will not be encountered when the program is enters the uncompiled state but will instead be encountered at some later time.

> For programs that use features like unsized arrays that can not be compiled until their array sizes are set, it is good practice to change the default behavior of compilation to CG_COMPILE_MANUAL so that cgCreateProgram() or cgCreateProgramFromFile() do not unnecessarily encounter and report compilation errors.

> ## Shared Parameters (Context Global Parameters)

> Version 1.2 of the runtime introduces parameters that may be shared across programs in the same context via a new binding mechanism. Once shared parameters are constructed and bound to program parameters, setting the value of the shared parameter will automatically set the value of all of the program parameters they are bound to.

> Shared parameters belong to a CGcontext instead of a CGprogram. They may be created with the following new entry points :

>     CGparameter cgCreateParameter(CGcontext ctx, CGtype type);
>     CGparameter cgCreateParameterArray(CGcontext ctx, CGtype type,
>                                        int length);
>     CGparameter cgCreateParameterMultiDimArray(CGcontext ctx, CGtype type,
>                                                int dim, const int *lengths);

> They may be deleted with :

>         void cgDestroyParameter(CGparameter param);

> After a parameter has been created, its value should be set with the cgSetParameter*() routines described in the literalization section above.

> Once a shared parameter is created it may be associated with any number of program parameters with the call:

>         void cgConnectParameter(CGparameter from, CGparameter to);

> where ``from'' is a parameter created with one of the cgCreateParameter() calls, and ``to'' is a program parameter.

> Given a program parameter, the handle to the shared parameter that is bound to it (if any) can be found with the call:

>         CGparameter cgGetConnectedParameter(CGparameter param);

> It returns NULL if no shared parameter has been connected to ``param''.

> There are also calls that make it possible to find the set of program parameters to which a given shared parameter has been connected to. The entry point:

>         int cgGetNumConnectedToParameters(CGparameter param);

> returns the total number of program parameters that ``param'' has been conencted to, and the entry point:

>         CGparameter cgGetConnectedToParameter(CGparameter param, int index);

> can be used to get CGparameter handles for each of the program parameters to which a shared parameter is connected.

> A shared parameter can be unbound from a program parameter with :

>         void cgDisconnectParameter(CGparameter param);

> The context in which a shared parameter was created can be returned with:

>         CGcontext cgGetParameterContext(CGparameter param);

> And the entrypoint:

>         CGbool cgIsParameterGlobal(CGparameter param);

> can be used to determine if a parameter is a shared (global) parameter.

> ## Shader Interface Support

> From the runtime's perspective, shader interfaces are simply struct parameters that have a CGtype associated with them. For example, if the following Cg code is included in some program source compiled in the runtime :

>     interface FooInterface
>     {
>       float SomeMethod(float x);
>     }

>     struct FooStruct : FooInterface
>     {
>       float SomeMethod(float x);
>       {
>         return(Scale * x);
>       }

>       float Scale;
>     };

> The named types FooInterface and FooStruct will be added to the context. Each one will have a unique CGtype associated with it. The CGtype can be retrieved with :

>     CGtype cgGetNamedUserType(CGprogram program, const char *name);
>     int cgGetNumUserTypes(CGprogram program);
>     CGtype cgGetUserType(CGprogram program, int index);

>     CGbool cgIsParentType(CGtype parent, CGtype child);
>     CGbool cgIsInterfaceType(CGtype type);

> Once the CGtype has been retrieved, it may be used to construct an instance of the struct using cgCreateParameter. It may then be connected to a program parameter of the parent type (in the above example this would be FooInterface) using cgConnectParameter.

> Calling cgGetParameterType on such a parameter will return the CG_STRUCT to keep backwards compatibility with code that recurses parameter trees. In order to obtain the enumerant of the named type the following entry point should be used :

>         CGtype cgGetParameterNamedType(CGparameter param);

> The parent types of a given named type may be obtained with the following entry points :

>     int cgGetNumParentTypes(CGtype type);
>     CGtype cgGetParentType(CGtype type, int index);

> If Cg source modules with differing definitions of named types are added to the same context, an error will be thrown.

> XXX update for new scoping/context/program local definitions stuff XXX

> ## Updated Parameter Management Routines

> XXX where should these go?

> Some entrypoints from before have been updated in backwards compatible ways

>     CGparameter cgGetFirstParameter(CGprogram program, CGenum name_space);
>     CGparameter cgGetFirstLeafParameter(CGprogram program, CGenum name_space);

> like cgGetNamedParameter, but limits search to the given name_space (CG_PROGRAM or CG_GLOBAL)...

>     CGparameter cgGetNamedProgramParameter(CGprogram program, CGenum name_space,
>                                            const char *name);