2015-10-16 6 views
7

In Microsofts example für die Verwendung des PixelShader verwenden sie ein Singleton. Ich habe das gleiche Muster in other places gesehen, und hier sagen, dass sieSollte ein Singleton PixelShader eine Best Practice sein?

Die Pixel-Shader in einem privaten statischen Feld _pixelShader gespeichert ist. Dieses Feld ist statisch, da eine Instanz des kompilierten Shader-Codes für die gesamte Klasse ausreicht.

Bei Verwendung dieses Musters sind mehrere Speicherprobleme aufgetreten. Der PixelShader ist involviert ist Ereignisbehandlung, die nicht immer korrekt gelöscht wird. Wir mussten freeze sie, und sah eine Verbesserung. Wir mussten von Hand einiger Abteilungen tun

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

Und auch jetzt unter Stress gibt es nach wie vor Speicherlecks in diesem Bereich. Weiß jemand, ob der PixelShader schwere Ressourcen nutzt, die den Einsatz eines Singletons wert sind?

Antwort

1

Definitiv NEIN. Der Grund ist jedoch nicht mit PixelShader selbst, sondern seine Verwendung in ShaderEffect.
Fast alle Implementierungen von benutzerdefinierten Shader-Effekten für WPF basieren auf Microsoft .NET 3.5-Beispielen, die für .NET 4.0 nicht aktualisiert wurden. Es war in Ordnung Singleton PixelShader Instanz für alle Effekte, die nur ps_2_0 Shader unterstützt. Mit .NET 4.0 hat Microsoft die Unterstützung für ps_3_0 Pixelshader (für GPU-beschleunigte Geräte) eingeführt und damit Speicherlecks in die Klasse ShaderEffect eingeführt.
ShaderEffect verfolgt seine PixelShader-Eigenschaft und überprüft, dass es keine ps_3_0-Register für ps_2_0 Bytecode durch starke Subskription zu PixelShader internen Ereignis namens _shaderBytecodeChanged. Daher dient Singleton PixelShader, das von mehreren ShaderEffect Instanzen verwendet wird, als Domination Root für GC und übergibt alle Objekte, die mit einer Instanz von entsprechenden ShaderEffect verwendet wurden. Das ist known memory leak, die nicht behoben werden.
Wenn Sie ohne Lecks möchten PixelShader als Singleton verwenden, dann müssen Sie Laufzeit verwenden, Hacking: jedes Mal, PixelShader Instanz PixelShader Eigenschaft ShaderEffect Klasse zugeordnet wird, sollte _shaderBytecodeChanged Feld PixelShader Instanz manuell gelöscht werden, zB:

Natürlich können diese Operationen optimiert werden, indem Hilfsmethoden zur Laufzeit von DynamicMethod Infrastruktur oder ähnlichen Mechanismen generiert werden. Dies sollte jedoch nur für Shader verwendet werden, die definitiv ps_2_0 oder definitiv ps_3_0

sind