本例子是DirectX示例【StateManager Sample】
前言
StateManager Sample(状态管理器[0])
This sample demonstrates how to implement a set of callbacks using the ID3DXEffectStateManager to measure the number and types of state changes in a render loop managed by the effect system. The sample also demonstrates how to use the callbacks to override the default state management, which gives an application the option of implementing a custom approach to state filtering. An application that is CPU-bound is very likely to improve performance dramatically by controlling the amount of redundant state changes that occur in a complex render loop.
这个例子展示了如何使用ID3DXEffectStateManager 的回调函数,对效果系统(Effect System[1])管理的一个渲染周期进行状态改变次数和类型的监控。 这个例子同样展示了如何使用回调函数来重载默认的状态管理器,这种方式可以让用户自定义状态过滤(state filtering)。在一个比较复杂的渲染周期中,减少冗余的状态改变,是极可能改善基于CPU-bound应用的性能。How The Sample Works
This sample renders a scene composed of several mesh objects including a gazebo, trees, rocks, terrain, and a skybox. Each mesh may be composed of multiple materials (snow, wood, etc). Each material is implemented by a different effect. Because of the scene complexity, the render sequence has many state changes to render the variety of materials and objects. The render sequence is created after calling these functions in OnCreateDevice:
- BuildSceneFromX - This method loads the scene .x file, which specifies each of the meshes and their world transform. Each mesh then loads it's corresponding materials, which consists of an effect instance and the associated textures (if any).
- BuildSceneFromX-这个方法加载.x文件并添加到场景中,加载后会产生对应的Mesh并初始化它在场景中的位置。每个模型同时会加载模型的材质信息列表,一个材质信息包含一个效果实例(effect instance)还有它的材质(如果存在)(这个x模型非常规x模型,还扩展了其他信息)
- QueueAndSortRenderables - This method does two things. First, it adds to the render queue all the state changes necessary to render the scene. Second, it reorders the queue according to the type of device, and the state manager.
- QueueAndSortRenderables -这个方法做两件事情。一,它把渲染场景需要的状态改变全部添加到渲染队列中。二,对渲染队列和状态管理器进行排序,排序的方法会根据设备的类型。
- SetStateManager - This method propagates the state manager to each of the effects in preparation for rendering
- SetStateManager - 这个方法在每个效果渲染前设置它的状态管理器。
The sample demonstrates the benefits of filtering redundant state changes with a per device. When a device is created (IDirect3D9::CreateDevice), the type of device is specified with D3DDEVTYPE. A pure device (created with D3DCREATE_PUREDEVICE) filters a smaller subset of possible state change commands. It is very fast because is essentially streams the pipeline commands striaght to the hardware. A pure device does not do any validation of parameters, and does little or no redundant state filtering. In constrast, a non-pure device (created without D3DCREATE_PUREDEVICE) will check each state change for redundancy, and discard them. This reduces the amount of work that the device will need to perform.
这个例子展示了通过过滤掉冗余的状态改变而带来的优势。当一个device创建的时候会设定一个D3DDEVTYPE值。一个The ID3DXEffectStateManager makes it possible to write custom user handlers for state changes. You can measure the number of state changes, that are happening, or even write handlers that perform custom processing (such as filtering out redundant state changes). This is precisely what the StateManager sample does. When you run the sample, it defaults to: running a pure device, and filtering redundant states with ID3DXEffectStateManager. This is done by creating a CPureDeviceStateManager class which derives from ID3DXEffectStateManager.
本例子中:
State Changes(状态改变数) | Filtered State Changes(过滤的状态改变数) | Number of Rocks(石头的个数) | % Reduction in State Changes(减少状态改变比例) |
---|---|---|---|
120 | 38 | 1 | -31 |
7971 | 3856 | 200 | -48 |
Another Performance Tip: Reordering The Render Sequence
In addition to filtering redundant state changes, another option to improve performance is to re-order the render sequence. This can have an impact especially on a non-pure device, or in a scenario that is more limited by the amount of matrix transforms that are set (as opposed to the number of materials used). For example, here is a render sequence that is ordered by each mesh object:
除了减少多余的状态改变,另外一个改善性能的是方法是对渲染序列进行排序。这么做对一个非纯设备(non-pure device)尤其有用,还有对那些限定转换矩阵数量的场景(而不是限定使用材质的数量)。例如,下面是一个根据每个模型进行排序的渲染序列代码。
// Render each mesh object For each instance of mesh x Setup transforms (ID3DXEffect SetMatrix) For each material of mesh x Set up material (ID3DXEffect Begin/BeginPass) Draw
This is the same sequence re-ordered by material:
// Render each effect to minimize state changes For each material y Set up material (ID3DXEffect Begin/Begin Pass) For each instance of material y Set up transforms (ID3DXEffect SetMatrix) Draw
Each sequence is better in some situations and worse in others. An application that has lots of materials may reduce the number of redundant state changes by ordering by material.
一个(渲染)序列可能在一些场景中比较好,而另外一些场景中表现的比较差。一个应用可以通过对材质的排序从而减少渲染状态的改变。
For further information about measuring the performance of a CPU bound scenario using similar techniques to a profiler, see Accurately Profiling Direct3D API Calls (Direct3D 9).
更多的关于如何衡量基于CPU bound性的场景中的CPU性能 可以使用类似技术的工具,请参看Accurately Profiling Direct3D API Calls (Direct3D 9).翻译完毕,下面是代码讲解
1 类解释
CInstance | 一个可渲染对象,包括渲染数据(比如CMeshObject),它 的位置。 |
CMeshObject | 一个渲染模型,包括一组材质(vector <CMaterial*>),模型(mesh),名称(m_wsName)等 |
CRenderable | 等价于CInstance,只是提供了一些比较材质等的方法。 |
CMaterial | 材质,包括效果CEffect,还有纹理列表(<CTexture*> m_vecTextures) |
CTexture | 纹理信息,除了纹理数据,包括还有名称等 |
CEffect | 效果信息,处理Effect还包括Device.Transform的一些矩阵信息 |
CEffectInstance | 绑定模型材质到Effect中。 |
CStateManagerInterface | 实现接口ID3DXEffectStateManager,从而达到管理StateManager的效果,它下面实现两个具体的EffectStateManager, 一个是CPureDeviceStateManager,另外一个是CBaseStateManager,而CPureDeviceStateManager也是继承 CBaseStateManager |
CPureDeviceStateManager | 这个类维护State的参照表。包括samplerStage,textureStateStage,RenderStates。在设置State的时候设置哪些参数 发生了改变,并进行计数。 |
2 方法解释
- HRESULT CTexture::Create( LPDIRECT3DDEVICE9 pDevice, LPCWSTR wszFilename, CTexture** ppTexture )
- 创建纹理(会根据纹理的名称去重)(支持2D,3D材质的加载)
- HRESULT CTexture::GetNormalMapPtr( LPDIRECT3DBASETEXTURE9* ppTexture )
- 从一个高度图(height map)创建法线贴图
- STDMETHOD( SetRenderState )( THIS_ D3DRENDERSTATETYPE d3dRenderState, DWORD dwValue )
- 设置RenderState并且计算状态改变的量。同类型的还有SetSamplerState,SetTextureStageState
- HRESULT CEffect::SetStateManager( LPD3DXEFFECTSTATEMANAGER pManager )
- Effect对象设置StateManager。