克隆效果
克隆效果会创建效果的第二个几乎完全相同的副本。 请参阅以下单一限定符,了解其不精确的原因。 当想要在多个线程上使用效果框架时,效果的第二个副本很有用,因为效果运行时不是线程安全的,无法保持高性能。
由于设备上下文也是非线程安全的,因此不同的线程应将不同的设备上下文传递到 ID3DX11EffectPass::Apply 方法。
可以使用以下语法克隆效果:
ID3DX11Effect* pClonedEffect = NULL;
UINT Flags = D3DX11_EFFECT_CLONE_FORCE_NONSINGLE;
HRESULT hr = pEffect->CloneEffect( Flags, &pClonedEffect );
在上面的示例中,克隆的副本将封装与原始效果相同的状态,而不管原始效果处于什么状态。 具体而言:
- 如果 pEffect 已优化,则优化 pCloned 效果
- 如果 pEffect 具有一些用户管理的变量,则 pCloned Effect 将具有相同的用户托管变量, (请参阅下面的单一说明)
- 在 pEffect 中应用调用更新设备状态) 之前, (挂起的变量更新将在 pClonedEffect 中挂起
以下 Direct3D 11 设备对象是不可变的,或者效果框架永远不会更新,因此克隆的效果将指向与原始效果相同的对象:
- 状态块对象 (ID3D11BlendState、ID3D11RasterizerState、ID3D11DepthStencilState、ID3D11SamplerState)
- 着色器
- 类实例
- 纹理 (不包括纹理缓冲区)
- 无序访问视图
以下 Direct3D 11 设备对象都是不可变的,并且由效果运行时 (修改,除非用户管理或克隆效果) 中的单个;当非单个时,会创建这些对象的新副本:
- 常量缓冲区
- 纹理缓冲区
单个常量缓冲区和纹理缓冲区
请注意,此讨论同时适用于常量缓冲区和纹理,但为了便于阅读,假定使用常量缓冲区。
在某些情况下,常量缓冲区仅由一个线程更新,但由克隆效果设置的设备状态将使用此数据。 例如,main效果可能会更新从克隆效果中的着色器引用的世界和视图矩阵,这些着色器不会更改世界矩阵和视图矩阵。 在这些情况下,克隆的效果需要引用当前常量缓冲区,而不是重新创建一个常量缓冲区。
可通过两种方法实现此所需结果:
- 对克隆效果使用 ID3DX11EffectConstantBuffer::SetConstantBuffer,使其由用户管理
- 在 HLSL 代码中将常量缓冲区标记为“单一”,强制在克隆后将效果运行时视为用户管理
上述两种方法之间存在两个差异。 首先,在方法 1 中,在调用 SetConstantBuffer 之前,将创建新的 ID3D11Buffer 和用户。 此外,在克隆效果中调用 UndoSetConstantBuffer 后,方法 1 中的变量将指向新创建的缓冲区 (将在 Apply) 上更新该效果,而方法 2 中的变量将继续指向原始缓冲区, (应用) 不更新它。
请参阅 HLSL 中的以下示例:
cbuffer ObjectData
{
float4 Position;
};
single cbuffer ViewData
{
float4x4 ViewMatrix;
};
克隆时,克隆效果将为 ObjectData 创建新的 ID3D11Buffer,并在 Apply 上填充其内容,但引用 ViewData 的原始 ID3D11Buffer。 可以通过设置 D3DX11_EFFECT_CLONE_FORCE_NONSINGLE 标志,在克隆过程中忽略单个限定符。
相关主题