GPU Shader Plugins for RenderManJune 2006 |
The PRMan GPU shading plugin executes user-defined GPU shaders inside the PRMan shading engine. The GPU shader executes on exactly the same shading samples as the CPU shading system, so results from GPU-shaded renders will be the same quality as CPU-based shading. The GPU shaders are compiled to PRMan shader plugin and called from RSL in the same way that C/C++ plugin functions are called.
Please note that this plugin is currently experimental and is supported on only a subset of PRMan platforms. We are providing this plugin as a tool for our customers to evaluate the benefit of GPU-accelerated shading in their preview or final frame renders.
Users intending to write GPU shaders will need to learn the Cg shading language. There are a large number of Cg tutorial resources available online and in print. The free Cg compiler documentation (available from developer.nvidia.com) comes with a tutorial book in PDF form. For a printed reference, see "The Cg Tutorial," "GPU Gems," or "GPU Gems 2.". Lastly, a large number of Cg shaders are available online at www.shadertech.com.
setenv LD_LIBRARY_PATH $RMANTREE/etcor to extend the existing path:
setenv LD_LIBRARY_PATH $RMANTREE/etc:$LD_LIBRARY_PATH
LD_LIBRARY_PATH=$RMANTREE/etc export LD_LIBRARY_PATH
LD_LIBRARY_PATH=$RMANTREE/etc:$LD_LIBRARY_PATH export LD_LIBRARY_PATH
void myCgShader( uniform float a,// uniform float input float3 b, // varying float3 input out float3 c )// varying float3 output { c = a * b; }
gshader myCgShader.cg
plugin "myCgShader"; surface myRslShader ( uniform float a = .5; uniform color b = (1,1,1) ) { myCgShader( a, b, Ci ); }
shader myRslShader.sl
Display "test.tiff" "tiff" "rgb" Projection "perspective" "fov" 40 Rotate -90 1 0 0 Translate 0 -5 0 WorldBegin Surface "myRslShader" Sphere 1 -1 1 360 WorldEnd
prman -t:1 test.rib
// Cg Example Texture Use: void myCgShader( uniform sampler2D tex, float3 coord, out float3 result ) { result = tex2D(tex, coord.xy).xyz; } // RSL Example Texture Use. Note that point must be cast to color. myCgShader( "someTexture", color P, Ci );
If someTexture is a PRMan texture, the GPU runtime automatically loads it into GPU memory. Alternatively, users may manually load and configure GPU textures at startup time. This procedure is described in Section 6.2.
Note that the PRMan software shading engine is capable of handling much larger textures than can be used with a GPU. For this reason, the intended uses of GPU textures include lookup tables (e.g. for noise), pre-rendered shadow maps, small volumes (e.g., volume rendering or light transport approximations), etc.
NOTE: Cg parameter names beginning with _GSHADER_ are reserved by gshader. You should not name any shader parameters beginning with this string.
Cg Type RSL Type float float float3 color float4x4 matrix samplerTD (T = 1D, 2D, 3D, CUBE) string
input uniform float float3 float4x4 sampler1D sampler2D sampler3D samplerCUBE RxShadow input varying float float3 output varying float float3
The system also supports arrays of uniform and varying inputs. Varying output arrays are not supported.
Resource Limit Textures 14 Uniform and Varying Inputs 254 total Outputs 4 total
NOTE: These limits apply to the RenderMan GPU plugin used with an NVIDIA NV4x GPU.
To use a PRman texture in a GPU shader, simply declare the corresponding Cg texture type (e.g., sampler2D or sampleCUBE) and call the GPU plugin function from RSL with the name of the texture.
For example, the following Cg shader use a 2D texture:
void gpuTexShader( uniform sampler2D tex, float s, float t, out float3 result ) { result = tex2D(tex, float2(s,t)).xyz; }
and the following RSL shader calls the above shader:
plugin "gpuTexShader"; surface myRslShader (uniform string texName = "";) { gpuTexShader( texName, s, t, Ci ); }
Similarly, a cube map GPU lookup is performed as:
void gpuCubeShader( uniform samplerCUBE tex, float3 coord, out float3 result ) { result = texCUBE(tex, coord).xyz; }
GPU shaders can use mipmapped PRMan textures if texture coordinate derivatives are computed in PRMan. The following Cg shader demonstrates this usage:
void gpuMipShader( uniform sampler2D mipTex, float s, float t, float ds, float dt, out float3 result ) { result = tex2D(mipTex, float2(s,t), ds, dt).xyz; }
and is called by the following RSL shader:
plugin "gpuMipShade"; surface mipRslShader( uniform string texName = "" ) { gpuMipShader( texName, s, t, Du(s), Dv(t), Ci ); }
Note that GPU mipmap lookups are approximate and may produce artifacts relative to PRMan mipmapping.
The GPU shading system handles PRMan shadow maps differently than other textures in order to facilitate shadow lookups. The system automatically loads the shadow matrices, their inverse matrices, and provides convenience shadow lookup functions. To use a PRMan shadow map in a Cg shader:
#include "rmanGpuStdLib.h" void gpuShadow( uniform RxShadow shadow, float3 ptInWorldSpace, out float isInLight ) { isInLight = shadow.vTex2D_D24(ptInWorldSpace); }When compiling, specify the following include path:
gshader -I$RMANTREE/include gpuShadow.cg
Note that we declare the shadow map with the Cg structure "RxShadow" instead of "sampler2D." The RxShadow struct and other utility functions are defined in the Cg header "rmanGpuStdLib.h". This file is included in the RenderMan Pro Server developer kit. The RxShadow lookup is point sampled. Percentage closer filtering may be implemented by manually multisampling the shadow for higher-quality shadows.
If the shadow map is a GL_DEPTH_COMPONENT texture, use the "vTex2D_24" method to perform a shadow map lookup based on a point in world space. If the shadow map is a 1-component (alpha) fp32 texture (not a depth texture), use the vTex2D_FP32 method. (This makes the z-values linear, not perspective-corrected. It is easier to apply a shadow map bias in this space than in the OpenGL-style perspective-corrected shadow map.) This method takes a "bias" argument that works identically to the bias used in PRMan shadow calls.
The PRMan-to-GPU texture system currently has the following limitations:
void myCgShader( uniform float a, // uniform float input uniform float3 b, // uniform vector input uniform float4x4 c, // uniform matrix input uniform sampler1D texA,// 1D texture uniform sampler2D texB,// 2D texture uniform sampler3D texC,// 3D texture uniform samplerRECT texD,// RECT texture uniform samplerCUBE texE,// Cube map texture uniform RxShadow texF,// PRMan shadow map float d, // varying float input float3 e, // varying vector input out float f, // varying float output out float3 g ) // varying float3 output { }
Initialization routines for GPU plugins must be first compiled in a separate object file, and then included in the gshader compilation of the GPU shader. The complete instructions for this process are below:
#include "RslPlugin.h" extern "C" { void myInitFunction(RixContext* context) { ... } }
g++ -c -fPIC -O3 -I$RMANTREE/include myInitFunction.cpp
gshader myCgShader.cg -init myInitFunction -ldArgs "myInitFunction.o"
To use an arbitrary OpenGL texture with the GPU shading system, create an OpenGL texture in a user-defined initialization function (Section 6.1). Configure the OpenGL texture object, then associate it with a name string and register it by making the following API call:
void AddTextureGPU( const char* texNameStr, GLenum oglTexType, GLenum oglInternalFormat, GLuint oglTexId );The texture can then be used like a native PRMan texture (e.g., by passing "textureName" as the RSL argument for a GPU shader plugin expecting a corresponding texture).
The GPU memory allocation system defines the five following RSL functions:
float gpuAllocFloat() vector gpuAllocVector() normal gpuAllocNormal() point gpuAllocPoint() T gpuRead( T output ) [T = float, color, vector, normal, point] void gpuFree( T gpuMemPtr ) [T = float, color, vector, normal, point]These functions are defined in a shader plugin (gpuStdLib.so) that must be declared by any shader that uses them (see below).
The gpuAlloc calls return a pointer to GPU memory. This pointer can then be passed to any GPU call in place of a varying input or output parameter. A GPU-based variable can be copied to a CPU-based RSL variable by calling gpuRead. Users must free the memory allocated to that pointer by passing it to gpuFree before the end of the RSL shader. The GPU pointer value only has meaning when passed to GPU shaders or memory management calls and should not be used in other RSL expressions.
We do support input arrays of GPU-allocated temporaries, but it is forbidden to mix GPU-based temporaries with CPU-based temporaries in the same array. The results of doing so are undefined.
// Import GPU allocation plugin. plugin "gpuStdLib"; // Allocate varying variables in GPU memory. color gpuTmp1 = gpuAllocColor(); color gpuTmp2 = gpuAllocColor(); // Compute intermediate results in GPU memory. myFirstGpuCall(Cs, gpuTmp1); // Second pass reads and writes GPU memory mySecondGpuCall(gpuTmp1, gpuTmp2); // Copy GPU memory to CPU memory. // (Could have passed Ci as output instead.) Ci = gpuRead(gpuTmp2); // Free GPU memory gpuFree(gpuTmp1); gpuFree(gpuTmp2);When compiling shaders that use the built-in gpuStdLib.so plugin, be sure to specify the built-in shader plugin directory as an include path:
shader -I$RMANTREE/lib/shaders/plugins myRslShader.slAlso, make sure that the built-in shader plugin directory is included in the shader search path. This can be accomplished by adding $RMANTREE/lib/shaders/plugins to the /standardshaderpath in the rendermn.ini file (located in $RMANTREE/etc).
The simplest usage is:
gshader myShader.cgIf the Cg shader includes the Cg header rmanGpuStdLib.h, specify the following include path:
gshader -I$RMANTREE/include myShader.cgTo compile with a user-defined initialization function called myInitFunction that has been compiled to myInitFunction.o:
gshader myCgShader.cg -init myInitFunction -ldArgs "myInitFunction.o"
For more advanced usage, the complete set of command line options for gshader are described below.
-h Print this message -v Verbose output -I Include path for Cg and C/C++ compilers -cc Full bin path for C/C++ compiler (default 'cc') -ld Full bin path for C/C++ linker (default 'ld') -cgcArgs "args" Arguments for Cg compiler -ccArgs "args" Arguments for C/C++ compiler -ldArgs "args" Arguments for C/C++ linker -init name Scoped name for user-defined init function -nodso Do not build DSO. Just run Cg compiler. -cgw Write wrapped Cg shader to .cgw file -params Write parameter .gpp file
Pixar
Animation Studios
|