Tutorials Articles Misc

Cg and HLSL FAQ [Monday, June 02nd, 2003 - Alex]

Download Cg and HLSL FAQ as Text

                      A Cg & HLSL Shading Language FAQ
                            v0.003 June 6, 2003


This FAQ was created and is maintained by Alex (alexz@FusionIndustries.com). 
Any comments, questions, additions and corrections are encouraged and 
welcomed.

The latest version of this FAQ can be found at:
  www.FusionIndustries.com

  Japanese translation by Yukio Andoh - andoh AT opengl.com
  www.gimlay.org/~andoh/cg/faq/cg-hlsl-faq.html

This FAQ may be freely distributed or copied.

This FAQ is divided up into the following sections and questions:

 1. The Cg/HLSL Language
 2. Profiles
 3. Semantics
 4. Shader Entry Point (main())
 5. Vertex Shaders
 6. Fragment Shaders
 7. Interfacing C/C++ and OpenGL with Cg
 8. Miscellaneous
 9. References
10. Bibliography
11. Change log

-------------------------------------------------
1. The Cg/HLSL Language
-------------------------------------------------
1.1:  What's the difference between nVidia's Cg and Microsoft's HLSL 
      (High Level Shading Language)?

A:    Cg and HLSL are actually the same language! Cg/HLSL was co-developed
      by nVidia and Microsoft. They have different names for branding 
      purposes. HLSL is part of Microsoft's DirectX API and only compiles 
      into DirectX code, while Cg can compile to DirectX and OpenGL. 
      
      In this FAQ, Cg and HLSL can be used interchangably.


-------------------------------------------------
2. Profiles
-------------------------------------------------
2.1:  When a shader is called, how does Cg know whether to treat it as a 
      vertex or fragment shader?

A:    When a shader is loaded, one of the parameters allows the programmer 
      to specify if it is a vertex or fragment shader. Also, the type of 
      shader is specified when it is used.

      For example (using C/C++):

      ...
      CGprogram VProgram = cgCreateProgramFromFile(..."vertex_shader.cg"...);
      CGprofile profile = CG_PROFILE_VP20; // set globally
      ...
      void draw_loop()
      {
        cgGLBindProgram(VProgram);  // Binds shader to OpenGL calls
        cgGLEnableProfile(profile); // Tells Cg if it is a vertex 
                                    // or fragment shader 
          // your drawing code goes here
          // ie glBegin(...); glVertex3f(...); glEnd();
        cgGLDisableProfile(profile); // Unbinds shader
      }


2.2:  Which profile types are supported?

A:    This depends on what the Cg programming has been compiled for and the 
      hardware the program is running on. 
      
      The possible profiles are supported by the Cg compiler [1] (as of 
      this writing):
      * DirectX Vertex Shader 2.x Profiles (vs_2_*)
      * DirectX Pixel Shader 2.x Profiles (ps_2_*)
      * OpenGL ARB Vertex Program Profile (arbvp1)
      * OpenGL ARB Fragment Program Profile (arbfp1)
      * OpenGL NV_vertex_program 2.0 Profile (vp30)
      * OpenGL NV_fragment_program Profile (fp30)
      * DirectX Vertex Shader 1.1 Profile (vs_1_1)
      * DirectX Pixel Shader 1.x Profiles (ps_1_*)
      * OpenGL NV_vertex_program 1.0 Profile (vp20)
      * OpenGL NV_texture_shader and NV_register_combiners Profile (fp20)

      The profiles in CG are named slightly differently. For example, 
      the vp20 profile is called CG_PROFILE_VP20.

2.3:  Which profile is the best one to use?

A:    It depends on the features you want, the development hardware, and 
      the target hardware. 

      Using the most advanced profile (vs_2_*,vp30,etc) will most likely be
      the fastest and most powerful, but it will only run on the latest
      hardware.

      Using the older profiles (vs_1_*,vp20,etc) will run on older hardware,
      but may impose certain restrictions due to the limitations of hardware
      and might not be fully optimized for the latest hardware.

      The best way would be to have a code path for each type of shader and
      select which profile to use at run-time, by querying the graphics
      hardware to see which profiles it can support.

-------------------------------------------------
3. Semantics
-------------------------------------------------
3.1:  Why do we attach semantics to parameters and variables?

A:    Semantics are hints which tell the Cg compiler that the variables have
      access to read and/or write to the registers that contain the current
      vertex, color, texture coordinates, etc when the shader is called.
      Without semantics, shaders couldn't interact with the states and data
      that the underlying graphics sytem (OpenGL/DirectX) provide.

3.2:  When do we use semantics?

A:    Parameters with attached semantics are only considered by Cg when used
      with main(), otherwise they are ignored. Also, semantics can be
      attached to the return value of functions. 
      
      For example:

      float4 main() : COLOR
      {
          return float4(1.0, 1.0, 0.0, 1.0);
      }

3.3:  What are all the semantics available to be used?

A:    The semantics available in all profiles are: POSITION, NORMAL,
      BINORMAL, BLENDINDICES, BLENDWEIGHT, TANGENT, PSIZE, TEXCOORD0-
      TEXCOORD7 
      
      In addition, the following is a partial list of semantics
      available for some of the profiles: 
      COLOR, COLOR0, DIFFUSE, COLOR1, SPECULAR, DEPTH, FOG 
      
      For a complete and detailed listing, refer to Appendix B in [1].
      
3.4:  Anything to watch out for with semantics?

A:    Input binding semantics and output binding semantics can not be mixed 
      within a single structure.

-------------------------------------------------
4. Shader Entry Point (main())
-------------------------------------------------
4.1:  Is there any special data structure, format, or variable name needed 
      for passing parameters to shaders?

A:    Some paramenters must have semantics bound to them, but otherwise 
      there are no special ways of using shaders.

4.2:  I don't see a function called main() in the shader code! How can it be
      called?

A:    By default, calling cgCreateProgramFromFile(...) assumes that the Cg
      file contains a function called main(). 
      
      However, the start of the shader program ("entry point") doesn't have
      to be called main(), as long as cgCreateProgramFromFile() is called
      with a parameter that tells what the name is of the "main()" function.
      
      In the following example, the main() function is called "MyMain()" and
      we tell Cg that when cgCreate...() is called.

      For example,
      MyShader.cg:
      void MyMain(...) {}

      MyCode.cpp:
      ...
      CGprogram Program = cgCreateProgramFromFile(context, 
                                                  CG_SOURCE,
                                                  "MyShader.cg",
                                                  profile,
                                                  "MyMain",
                                                  NULL );
      ...

4.3:  In most of nVidia's examples, I see a struct being passed to the
      shader's main function. How does Cg handle the struct containing
      different parameters and what does it do when some parameters aren't
      given?

      For example,

      struct appdata
      {
          float4 position   : POSITION;
          float3 normal     : NORMAL;
          float3 color      : DIFFUSE;
          float3 TestColor  : SPECULAR;
      };

      struct vfconn
      {
          float4 pos : POSITION;
          float4 col0 : COLOR0;
      };

      void main(appdata IN, ...)
      {
        vfconn OUT;
        ...
        return OUT;
      }

A:    The members of the struct have semantics specified, which connect the
      variables in the shader code to the underlying graphics system
      (OpenGL/DirectX).

      For example, the POSITION semantic means that the value is read from
      the register that hold the homogenous position of the vertex being
      passed to the shader.

      The benefit is that any struct or parameters can be passed to
      functions. If a struct like

      struct mydata
      {
        float4 position : POSITION;
        float3 color    : DIFFUSE;
      };
      void main(mydata m) {...}

      is passed to a function, then the function will only be able to access
      and manipulate the data associate with the registers that contain the
      POSITION and DIFFUSE values from the underlying graphics system
      (OpenGL/DirectX). 
      
      This also means that other registers, for example COLOR and
      TEXCOORD0, cannot be accessed or modified by that function.

4.4:  Why does nVidia use structs to pass and return their data to and from
      shaders?

A:    The motivation is the same as using structs in any programming language
      (like C/C++/Java). It is available to be used if desired, but it is not
      required.

4.5:  Does a struct containing parameters with semantics have to be passed to
      main()?

A:    No. They can be passed as parameters too.
      For example:
      void main( float4 color : COLOR ) {}

4.6:  In most of nVidia's examples, they use variables, such as "appdata IN",
      "vfconn OUT". Do the variable names have to be named IN and OUT?

A:    The variable names can be anything, as long as it is not a reserved
      keyword. Note that "in" and "out" are keywords. Variable names are
      case-sensitive.

4.7:  What's the relation of the previous question (4.6) to the keywords
      "in", "inout" and "out"? Why are they needed if data can be passed and
      returned like as in C?

A:    The keywords are available as a matter of convenience, so all 
      parameters can be in the function prototype.

      The keyword "in" is a modifier for a parameter which tells Cg that the
      parameter takes input when the shader is called.

      Similarly, the modifier "out" tells Cg the parameter contains the
      output of the shader.

      Finally, "inout" can contain both the input and output. 


      For example:
      
      void main( in  float4 inPos  : POSITION,
                 out float4 outColor: COLOR )

      {
        float4 newPos = inPos + /* ... */;
        outColor = /* ... */
      }

-------------------------------------------------
5. Vertex Shaders
-------------------------------------------------
5.1:  Are there any restrictions on the types of parameters vertex shaders 
      can take?

A:    The short answer: No. 
      The longer answer: The only limitation is that for a given shader,
      semantics assigned to variables can only be used once for input
      variables and once for output variables.

5.2:  Are there any restrictions on the return value of vertex shaders?

A:    Vertex shaders must return a four-component (xyzw) vertex with a
      POSITION binding semantic, which the rasterizer uses. It can be
      returned within a struct or by using the "out" keyword in the parameter
      list.

-------------------------------------------------
6. Fragment Shaders
-------------------------------------------------
6.1:  Are there any restrictions on the types of parameters fragment shaders
      can take?

A:    The short answer: No. 
      The longer answer: The only limitation is that for a given shader,
      semantics assigned to variables can only be used once for input
      variables and once for output variables.

6.2:  Are there any restrictions on the return value of fragment shaders?

A:    Fragment shaders must return a color with four components (rgba) with a
      COLOR binding semantic and optionally depth components with a DEPTH
      binding semantic. It can be returned within a struct or by using the
      out keyword in the parameter list.

-------------------------------------------------
7. Interfacing C/C++ and OpenGL with Cg
-------------------------------------------------
7.1:  How are parameters in Cg accessed from C/C++?

A:    By using cgGetNamedParameter(). Refer to example following the next 
      questions. Additional ways of accessing parameters can be found in [1].

7.2:  How are parameters in Cg set?

A:    By using cgGLSetParameter{1234}{fdv}(), which uses a naming convention
      similar to OpenGL. There are additional ways of setting data, which can
      be found in [1].

      For example, the following C code snippet creates a handle to the
      variable called "Diffuse" in the Cg program and sets its value to 
      (1,0,0) (which is red).

      ...
      // assume valid Cg program source file and create a handle to it
      CGprogram Program = cgCreateProgramFromFile(...);
      
      // "glue" DiffuseParam to the parameter named "Diffuse" in the Cg code
      CGparameter DiffuseParam = cgGetNamedParameter(Program, "Diffuse");
      
      // Use "DiffuseParam" to update the value in the Cg shader code
      cgGLSetParameter3f(DiffuseParam, 1,0,0);
      ...


7.3:  When should Cg programs be called from C/C++/OpenGL?

A:    Cg programs should be called in the drawing loop where you want the
      shader to be applied and disabled at the end of the draw loop (similar
      to glBegin() and glEnd()).

      For example:

      void draw()
      {
        cgGLBindProgram( program );   // attach the shader
        cgGLEnableProfile( profile ); // specifies vertex or fragment shader

          // your drawing code goes here
          glBegin(GL_TRIANGLES);
            glColor3f(...);
            glVertex3fv(...);
          glEnd();


        cgGLDisableProfile(profile); // stops using shader
      }

-------------------------------------------------
8. Miscellaneous
-------------------------------------------------
8.1:  How can I write comments?

A:    The C/C++ commenting style is supported, which are single line 
      comments (//) and multi-line comments (/*...*/).

      For example
      float4 pos; // This is a comment
      float4 dif; /* This is another comment */
      float4 col; /* This is a
                     multiline comment */

-------------------------------------------------
9. References
-------------------------------------------------
Most of this information in this FAQ can be found in greater detail in [1].

www.nVidia.com/cg
www.cgshaders.org

-------------------------------------------------
10. Bibliography
-------------------------------------------------
[1] CG Toolkit User's Manual (Cg_Toolkit.pdf) www.nVidia.com

-------------------------------------------------
11. Change Log
-------------------------------------------------
v0.003 Jun 06, 2003: Added link to Japanese version by Yukio Andoh
                     andoh AT opengl.com
v0 002 Jun 03, 2003: Completed question 7.3, minor fixes.
v0.001 May 30, 2003: Created.

                -------------------------------------------
               Contact us at http://www.FusionIndustries.com
                         (C)2003 Fusion Industries
              

Workshops

At SIGGRAPH this year, nVidia will be running on workshops on beginning and advanced shader techniques.

I've been to several nVidia sessions at the Game Developers Conference for the last several years and they've been very useful. Not only are the talks in-depth and enlightening, but you get to talk with people on the nVidia dev team.

My background is in graphics research, so being able to discuss the techniques I'm researching and working on with the dev team has helped me learn how to take advantage of the graphics hardware and learn from the demos they've created.

Must-Have Books

(To come)



[ News || Links || Archives || Downloads || Projects || Gallery || Lore, etc ]