2015-10-16 25 views
7

在微軟的example中如何使用PixelShader他們使用的是單例。我在other places中看到了相同的模式,在這裏他們說應該使用單例PixelShader是否是最佳做法?

像素着色器存儲在私有靜態字段_pixelShader中。該字段是靜態的,因爲編譯着色器代碼的一個實例對於整個類是足夠的。

使用此模式時,我們已經看到了幾個內存泄漏問題。 PixelShader涉及的事件處理並不總是被正確清除。我們不得不freeze他們,並看到一些改善。我們不得不手動做一些分遣隊

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

即使在壓力下,該區域仍然存在內存泄漏。有沒有人知道PixelShader是否使用了大量資源,這些資源在使用單例時很麻煩?

回答

1

肯定沒有。但是,原因不在於PixelShader本身,而是其在ShaderEffect中的使用。
幾乎所有WPF自定義Shader效果的實現都基於Microsoft的.NET 3.5示例,該示例並未針對.NET 4.0進行更新。對於僅支持ps_2_0着色器的所有效果,使用單例PixelShader實例很好。在.NET 4.0中,微軟引入了對ps_3_0像素着色器(用於GPU加速設備)的支持,並且由此引入了ShaderEffect類中的內存泄漏。
ShaderEffect跟蹤其PixelShader屬性,並通過強預訂名爲_shaderBytecodeChanged的PixelShader內部事件來檢查它是否將ps_2_0字節碼的ps_3_0寄存器使用。因此,由多個ShaderEffect實例使用的單個實例PixelShader可用作GC的調教根節點,並更新與相應的ShaderEffect的任何實例一起使用的所有對象。那是known memory leak,這不會被修復。
如果你想用PixelShader如無泄漏單身,那麼你將不得不使用運行黑客:每PixelShader實例被分配到ShaderEffectPixelShader財產時,PixelShader實例_shaderBytecodeChanged字段應手動清除,例如:

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

當然,這些操作可以通過在運行時通過基礎設施或類似機制生成幫助程序方法來優化。但是,這應該只用於明確ps_2_0或絕對ps_3_0着色器

相關問題