FragmentLinker Sample

Description
This sample shows how to use the FragmentLinker class. Shader source code can be split into a series of shader fragments, which are compiled separately and linked together to form a complete shader; this linking stage is very efficient, making it suitable for runtime use. In this way a Direct3D application can custom-build an appropriate shader for the current graphics card.



Path
Source: Samples\Managed\Direct3D\FragmentLinker
Executable: Samples\Managed\Direct3D\bin\csFragmentLinker.exe

Sample Overview
Large-scale Direct3D applications commonly employ a large set of redundant shaders covering every supported fallback case for a given technique (often generated by uniform parameters) from which the appropriate shader for the current graphics hardware is selected at runtime. This approach can result in a large amount of compiled shaders being included with the application, only a small fraction of which are ever used on a given machine. Using shader fragments, the desired shader for the current graphics card can be built at runtime.

How does the sample work?
This sample links together one of two vertex shader fragments which handle projection (vertex animated or static) and one of two vertex shader fragments which handle vertex lighting (diffuse enabled or ambient only). These fragments are compiled once during initialization and are then linked together at runtime.

There are only a few steps which need to be followed when using shader fragments in your application:

  1. Create the FragmentLinker object
  2. Load and compile the shader fragments by calling GatherFragments, GatherFragmentsFromFile, or GatherFragmentsFromStream
  3. Add the compiled fragments to the linker's internal list with a call to FragmentLinker.AddFragments. This list defines the complete set of all fragments, from which a subset will be linked to create a shader.
  4. Retrieve handles of the fragments you want linked through calls to FragmentLinker.GetFragmentHandle
  5. Link together a subset of the added fragments by passing fragment handles to the FragmentLinker.LinkVertexShader, FragmentLinker.LinkPixelShader, or FragmentLinker.LinkShader method. These methods create an interface to a compiled shader which can be used for rendering.


The sample application performs the above steps upon device creation within the OnCreateDevice function:


// Create the fragment linker interface
fragmentLinker = new FragmentLinker(e.Device, 0);

// Compile the fragments to a buffer. The fragments must be linked together to form
// a shader before they can be used for rendering.
path = Utility.FindMediaFile("FragmentLinker.fx");
compiledFragments = Microsoft.DirectX.Direct3D.FragmentLinker.GatherFragmentsFromFile(path, null, null, shaderFlags);

// Build the list of compiled fragments
fragmentLinker.AddFragments(compiledFragments);

// Store the fragment handles
ComboBox cb1 = sampleUI.GetComboBox(Lighting);
cb1.Clear();
cb1.AddItem("Ambient", fragmentLinker.GetFragmentHandle("AmbientFragment"));
cb1.AddItem("Ambient & Diffuse", fragmentLinker.GetFragmentHandle("AmbientDiffuseFragment"));

ComboBox cb2 = sampleUI.GetComboBox(Animation);
cb2.Clear();
cb2.AddItem("On" , fragmentLinker.GetFragmentHandle("ProjectionFragment_Animated"));
cb2.AddItem("Off", fragmentLinker.GetFragmentHandle("ProjectionFragment_Static"));

// Link the desired fragments to create the vertex shader
LinkVertexShader();

The final linking step is performed within the LinkVertexShader helper function. In addition to being called upon device creation, this function is also called whenever the user changes a fragment combobox selection. The currently selected fragments are retrieved from the user interface controls, the shader is quickly linked, and the new shader is passed to the effect file:


private void LinkVertexShader()
{
    const int NumberFragments = 2;
    EffectHandle[] aHandles = new EffectHandle[NumberFragments];
    
    aHandles[0] = sampleUI.GetComboBox(Animation).GetSelectedData() as EffectHandle;
    aHandles[1] = sampleUI.GetComboBox(Lighting).GetSelectedData() as EffectHandle;

    // Link the fragments together to form a shader
    string errors;
    VertexShader vertexShader = fragmentLinker.LinkVertexShader("vs_1_1", shaderFlags, aHandles, out errors);

    // Associate this vertex shader with the effect object
    effect.SetValue("MyVertexShader", vertexShader);
}


Resources
The syntax for writing shader fragments is detailed in the "Writing HLSL Shaders" programming guide topic under the heading "Writing Shader Fragments" and on the reference page "Fragment Declaration Syntax".

More in-depth coverage of the process behind compiling and linking shader fragments is found in the "Using HLSL Shaders" programming guide topic under the heading "Building And Rendering Fragments".



Copyright (c) Microsoft Corporation. All rights reserved.