![]() |
![]() |
![]() |
This sample shows how to use the ID3DXFragmentLinker interface. 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 run-time use. In this way a Microsoft Direct3D application can custom-build an appropriate shader for the current graphics card.
Source: | (SDK root)\Samples\C++\Direct3D\FragmentLinker |
Executable: | (SDK root)\Samples\C++\Direct3D\Bin\FragmentLinker.exe |
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 run time. 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 run time.
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 run time.
There are only a few steps that need to be followed when using shader fragments in your application:
The sample application performs the above steps upon device creation within the OnCreateDevice function:
// Create the fragment linker interface V_RETURN( D3DXCreateFragmentLinker( pd3dDevice, 0, &g_pFragmentLinker ) ); // Compile the fragments to a buffer. The fragments must be linked together to form // a shader before they can be used for rendering. V_RETURN( D3DXGatherFragmentsFromFile( L"FragmentLinker.fx", NULL, NULL, g_dwShaderFlags, &g_pCompiledFragments, NULL ) ); // Build the list of compiled fragments V_RETURN( g_pFragmentLinker->AddFragments( (DWORD*)g_pCompiledFragments->GetBufferPointer() ) ); // Store the fragment handles CDXUTComboBox* pComboBox = NULL; pComboBox = g_SampleUI.GetComboBox( IDC_LIGHTING ); pComboBox->RemoveAllItems(); pComboBox->AddItem( L"Ambient", (void*) g_pFragmentLinker->GetFragmentHandleByName( "AmbientFragment" ) ); pComboBox->AddItem( L"Ambient & Diffuse", (void*) g_pFragmentLinker->GetFragmentHandleByName( "AmbientDiffuseFragment" ) ); pComboBox = g_SampleUI.GetComboBox( IDC_ANIMATION ); pComboBox->RemoveAllItems(); pComboBox->AddItem( L"On", (void*) g_pFragmentLinker->GetFragmentHandleByName( "ProjectionFragment_Animated" ) ); pComboBox->AddItem( L"Off", (void*) g_pFragmentLinker->GetFragmentHandleByName( "ProjectionFragment_Static" ) ); // Link the desired fragments to create the vertex shader V_RETURN( 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:
HRESULT LinkVertexShader() { HRESULT hr; const int NUM_FRAGMENTS = 2; D3DXHANDLE aHandles[ NUM_FRAGMENTS ] = {0}; aHandles[ 0 ] = (D3DXHANDLE) g_SampleUI.GetComboBox( IDC_ANIMATION )->GetSelectedData(); aHandles[ 1 ] = (D3DXHANDLE) g_SampleUI.GetComboBox( IDC_LIGHTING )->GetSelectedData(); // Link the fragments together to form a shader IDirect3DVertexShader9* pVertexShader = NULL; V_RETURN( g_pFragmentLinker->LinkVertexShader( "vs_1_1", g_dwShaderFlags, aHandles, NUM_FRAGMENTS, &pVertexShader, NULL ) ); // Associate this vertex shader with the effect object V_RETURN( g_pEffect->SetVertexShader( "MyVertexShader", pVertexShader ) ); SAFE_RELEASE( pVertexShader ); return S_OK; }
The syntax for writing shader fragments is detailed in Writing Shader Fragments and in the Fragment Declaration Syntax.
More in-depth coverage of the process behind compiling and linking shader fragments is found in Building And Rendering Fragments.