sho*_*ren 9 c# wpf pixel-shader
在Microsoft的如何使用PixelShader 的示例中,他们使用单例.我在其他地方看到了相同的模式,他们在这里说
像素着色器存储在私有静态字段_pixelShader中.此字段是静态的,因为已编译的着色器代码的一个实例足以满足整个类的要求.
使用此模式时,我们已经看到了几个内存泄漏问题.涉及的PixelShader是事件处理,并不总是被正确清除.我们不得不冻结它们,看到了一些改进.我们不得不手动做一些分离
// Attach/detach effect as UI element is loaded/unloaded. This avoids
// a memory leak in the shader code as described here:
element.Loaded += (obj, args) =>
{
effect.PixelShader = ms_shader;
element.Effect = effect;
};
element.Unloaded += (obj, args) =>
{
effect.PixelShader = null;
element.Effect = null;
};
Run Code Online (Sandbox Code Playgroud)
即使现在处于压力之下,该领域仍然存在内存泄漏.有没有人知道PixelShader是否使用重型资源值得使用单例?
绝对不。然而,原因不是PixelShader
它本身,而是它在ShaderEffect
.
几乎所有 WPF 自定义着色器效果的实现都基于 Microsoft 的 .NET 3.5 示例,这些示例未针对 .NET 4.0 进行更新。可以PixelShader
对所有效果使用单例实例,它仅支持 ps_2_0 着色器。在 .NET 4.0 中,Microsoft 引入了对 ps_3_0 像素着色器(适用于 GPU 加速设备)的支持,并因此在ShaderEffect
类中引入了内存泄漏。
ShaderEffect
通过强订阅 PixelShader 的内部事件 来跟踪其PixelShader
属性并检查它是否未将 ps_3_0 寄存器用于 ps_2_0 字节码_shaderBytecodeChanged
。因此,PixelShader
多个实例使用的单ShaderEffect
例充当 GC 的 Domination Root,并重新保留与相应 的任何实例使用的所有对象ShaderEffect
。这就是已知的内存泄漏,不会被修复。
如果您想在PixelShader
没有泄漏的情况下用作单例,那么您将不得不使用运行时黑客:每次将PixelShader
实例分配给类PixelShader
的属性时ShaderEffect
,都应手动清除实例_shaderBytecodeChanged
的字段,例如:PixelShader
var ei = typeof(PixelShader).GetEvent("_shaderBytecodeChanged",
BindingFlags.Instance | BindingFlags.NonPublic);
var fi = typeof(PixelShader).GetField(ei.Name,
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(pixelShader,null);
Run Code Online (Sandbox Code Playgroud)
当然,这些操作可以通过DynamicMethod
基础设施或类似机制在运行时生成辅助方法来优化。但是,这应该仅用于明确为 ps_2_0 或明确为 ps_3_0 的着色器