Should I use a singleton PixelShader?

In Microsoft's example , they use a singleton to use PixelShader. I saw the same pattern in other places , and here they say

The pixel shader is stored in the _pixelShader private static field. This field is static because one instance of compiled shader code is sufficient for the entire class.

We saw several memory leaks when using this pattern. PixelShader uses event processing, which is not always cleared correctly. We had to freeze them, and saw some improvement. We had to manually make some units

// 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; }; 

And even now under stress in this area there are still memory leaks. Does anyone know if PixelShader uses heavy resources, is it worth using a single?

+7
c # wpf pixel-shader
source share
1 answer

Definitely NO. However, the reason is not in PixelShader itself, but in use in ShaderEffect .
Almost all implementations of custom Shader Effects for WPF are based on Microsoft.NET 3.5 samples that have not been updated for .NET 4.0. It was good to use a singleton PixelShader instance for all effects, which only supported ps_2_0 shaders. With .NET 4.0, Microsoft introduced ps_3_0 pixel shader support (for GPU accelerated devices), and at the same time they introduced a memory leak in the ShaderEffect class.
ShaderEffect monitors its PixelShader property and verifies that it does not use ps_3_0 registers for ps_2_0 bytecode, thanks to a strong subscription to the PixelShader internal event called _shaderBytecodeChanged . Therefore, the singleton PixelShader used by multiple instances of ShaderEffect serves as the dominant root for the GC and saves all objects that were used with any instance of the corresponding ShaderEffect . This is a known memory leak that will not be fixed.
If you want to use PixelShader as a singleton without leaks, you have to use hacks at runtime: every time a PixelShader instance is assigned to the PixelShader property of the ShaderEffect class, the _shaderBytecodeChanged PixelShader field must be cleared manually, for example:

 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); 

Of course, these operations can be optimized by creating helper methods at run time by the DynamicMethod or similar mechanisms. However, this should only be used for shaders, which are certainly ps_2_0 or definitely ps_3_0

+1
source share

All Articles