克隆效果

克隆效果会创建效果的第二个几乎完全相同的副本。 请参阅以下单一限定符,了解其不精确的原因。 当想要在多个线程上使用效果框架时,效果的第二个副本很有用,因为效果运行时不是线程安全的,无法保持高性能。

由于设备上下文也是非线程安全的,因此不同的线程应将不同的设备上下文传递到 ID3DX11EffectPass::Apply 方法。

可以使用以下语法克隆效果:

ID3DX11Effect* pClonedEffect = NULL;
UINT Flags = D3DX11_EFFECT_CLONE_FORCE_NONSINGLE;
HRESULT hr = pEffect->CloneEffect( Flags, &pClonedEffect );

在上面的示例中,克隆的副本将封装与原始效果相同的状态,而不管原始效果处于什么状态。 具体而言:

  1. 如果 pEffect 已优化,则优化 pCloned 效果
  2. 如果 pEffect 具有一些用户管理的变量,则 pCloned Effect 将具有相同的用户托管变量, (请参阅下面的单一说明)
  3. 在 pEffect 中应用调用更新设备状态) 之前, (挂起的变量更新将在 pClonedEffect 中挂起

以下 Direct3D 11 设备对象是不可变的,或者效果框架永远不会更新,因此克隆的效果将指向与原始效果相同的对象:

  1. 状态块对象 (ID3D11BlendState、ID3D11RasterizerState、ID3D11DepthStencilState、ID3D11SamplerState)
  2. 着色器
  3. 类实例
  4. 纹理 (不包括纹理缓冲区)
  5. 无序访问视图

以下 Direct3D 11 设备对象都是不可变的,并且由效果运行时 (修改,除非用户管理或克隆效果) 中的单个;当非单个时,会创建这些对象的新副本:

  1. 常量缓冲区
  2. 纹理缓冲区

单个常量缓冲区和纹理缓冲区

请注意,此讨论同时适用于常量缓冲区和纹理,但为了便于阅读,假定使用常量缓冲区。

在某些情况下,常量缓冲区仅由一个线程更新,但由克隆效果设置的设备状态将使用此数据。 例如,main效果可能会更新从克隆效果中的着色器引用的世界和视图矩阵,这些着色器不会更改世界矩阵和视图矩阵。 在这些情况下,克隆的效果需要引用当前常量缓冲区,而不是重新创建一个常量缓冲区。

可通过两种方法实现此所需结果:

  1. 对克隆效果使用 ID3DX11EffectConstantBuffer::SetConstantBuffer,使其由用户管理
  2. 在 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 标志,在克隆过程中忽略单个限定符。

Direct3D 11) (效果