Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / Effects / ShaderEffect.cs / 1 / ShaderEffect.cs
//------------------------------------------------------------------------------ // Microsoft Windows Presentation Foundation // Copyright (c) Microsoft Corporation, 2008 // // File: ShaderEffect.cs //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Media; using System.IO; using System.Windows.Markup; using System.Windows.Media.Composition; using System.Windows.Media.Media3D; using System.Security; using System.Security.Permissions; using System.Runtime.InteropServices; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Media.Effects { public abstract partial class ShaderEffect : Effect { ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingTop { get { ReadPreamble(); return _topPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingTop", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _topPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingBottom { get { ReadPreamble(); return _bottomPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingBottom", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _bottomPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingLeft { get { ReadPreamble(); return _leftPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingLeft", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _leftPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingRight { get { ReadPreamble(); return _rightPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingRight", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _rightPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// To specify a shader constant register to set to the size of the /// destination. Default is -1, which means to not send any. Only /// intended to be set once, in the constructor, and will fail if set /// after the effect is initially processed. /// protected int DdxUvDdyUvRegisterIndex { get { ReadPreamble(); return _ddxUvDdyUvRegisterIndex; } set { WritePreamble(); if (_sentFirstTime) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderDdxUvDdyUvRegisterIndex)); } _ddxUvDdyUvRegisterIndex = value; WritePostscript(); } } ////// Tells the Effect that the shader constant or sampler corresponding /// to the specified DependencyProperty needs to be updated. /// protected void UpdateShaderValue(DependencyProperty dp) { if (dp != null) { WritePreamble(); object val = this.GetValue(dp); var metadata = dp.GetMetadata(this); if (metadata != null) { var callback = metadata.PropertyChangedCallback; if (callback != null) { callback(this, new DependencyPropertyChangedEventArgs(dp, val, val)); } } WritePostscript(); } } ////// Construct a PropertyChangedCallback which, when invoked, will result in the DP being /// associated with the specified shader constant register index. /// protected static PropertyChangedCallback PixelShaderConstantCallback(int floatRegisterIndex) { return (obj, args) => { ShaderEffect eff = obj as ShaderEffect; if (eff != null) { eff.UpdateShaderConstant(args.Property, args.NewValue, floatRegisterIndex); } }; } ////// Construct a PropertyChangedCallback which, when invoked, will result /// in the DP being associated with the specified shader sampler /// register index. Expected to be called on a Brush-valued /// DependencyProperty. /// protected static PropertyChangedCallback PixelShaderSamplerCallback(int samplerRegisterIndex) { return PixelShaderSamplerCallback(samplerRegisterIndex, _defaultSamplingMode); } ////// Construct a PropertyChangedCallback which, when invoked, will result /// in the DP being associated with the specified shader sampler /// register index. Expected to be called on a Brush-valued /// DependencyProperty. /// protected static PropertyChangedCallback PixelShaderSamplerCallback(int samplerRegisterIndex, SamplingMode samplingMode) { return (obj, args) => { ShaderEffect eff = obj as ShaderEffect; if (eff != null) { if (args.IsAValueChange) { eff.UpdateShaderSampler(args.Property, args.NewValue, samplerRegisterIndex, samplingMode); } } }; } ////// Helper for defining Brush-valued DependencyProperties to associate with a /// sampler register in the PixelShader. /// protected static DependencyProperty RegisterPixelShaderSamplerProperty(string dpName, Type ownerType, int samplerRegisterIndex) { return RegisterPixelShaderSamplerProperty(dpName, ownerType, samplerRegisterIndex, _defaultSamplingMode); } ////// Helper for defining Brush-valued DependencyProperties to associate with a /// sampler register in the PixelShader. /// protected static DependencyProperty RegisterPixelShaderSamplerProperty(string dpName, Type ownerType, int samplerRegisterIndex, SamplingMode samplingMode) { return DependencyProperty.Register(dpName, typeof(Brush), ownerType, new UIPropertyMetadata(Effect.ImplicitInput, PixelShaderSamplerCallback(samplerRegisterIndex, samplingMode))); } // Updates the shader constant referred to by the DP. Converts to the // form that the HLSL shaders want, and stores that value, since it will // be sent on every update. // We WritePreamble/Postscript here since this method is called by the user with the callback // created in PixelShaderConstantCallback. private void UpdateShaderConstant(DependencyProperty dp, object newValue, int registerIndex) { WritePreamble(); Type t = DetermineShaderConstantType(dp.PropertyType); if (t == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderConstantType, dp.PropertyType.Name)); } else { int registerMax = 32; if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(SRID.Effect_ShaderConstantRegisterLimit), "dp"); } if (t == typeof(float)) { MilColorF fourTuple; ConvertValueToMilColorF(newValue, out fourTuple); StashInPosition(ref _floatRegisters, registerIndex, fourTuple, 32, ref _floatCount); } else { // We should convert all acceptable types to float. Debug.Assert(false); } } // Propagate dirty this.PropertyChanged(dp); WritePostscript(); } // Updates the shader sampler referred to by the DP. Converts to the // form that the HLSL shaders want, and stores that value, since it will // be sent on every update. // We WritePreamble/Postscript here since this method is called by the user with the callback // created in PixelShaderSamplerCallback. private void UpdateShaderSampler(DependencyProperty dp, object newValue, int registerIndex, SamplingMode samplingMode) { WritePreamble(); if (newValue != null) { if (!(typeof(VisualBrush).IsInstanceOfType(newValue) || typeof(ImplicitInputBrush).IsInstanceOfType(newValue) || typeof(ImageBrush).IsInstanceOfType(newValue)) ) { // Note that if the type of the brush is ImplicitInputBrush and the value is non null, the value is actually // Effect.ImplicitInput. This is because ImplicitInputBrush is internal and the user can only get to the singleton // Effect.ImplicitInput. throw new ArgumentException(SR.Get(SRID.Effect_ShaderSamplerType), "dp"); } } // PS2.0 allows max 16, but some cards seem to have trouble with 16 samplers being set. // Restricting to 4 for now. if (registerIndex >= 4 || registerIndex < 0) // allow -1 for default { throw new ArgumentException(SR.Get(SRID.Effect_ShaderSamplerRegisterLimit)); } SamplerData sd = new SamplerData() { _brush = (Brush)newValue, _samplingMode = samplingMode }; StashSamplerDataInPosition(registerIndex, sd, 16); // Propagate dirty this.PropertyChanged(dp); WritePostscript(); } // Ensures that list is extended to 'position', and that // the specified value is inserted there. For lists of value types. private static void StashInPosition(ref List list, int position, T value, int maxIndex, ref int count) where T : struct { if (list == null) { list = new List (maxIndex); } if (list.Count <= position) { int numToAdd = position - list.Count + 1; for (int i = 0; i < numToAdd; i++) { list.Add((T?)null); } } if (!list[position].HasValue) { // Going from null to having a value, so increment count count++; } list[position] = value; } // Ensures that _samplerData is extended to 'position', and that // the specified value is inserted there. private void StashSamplerDataInPosition(int position, SamplerData newSampler, int maxIndex) { if (_samplerData == null) { _samplerData = new List (maxIndex); } if (_samplerData.Count <= position) { int numToAdd = position - _samplerData.Count + 1; for (int i = 0; i < numToAdd; i++) { _samplerData.Add((SamplerData?)null); } } if (!_samplerData[position].HasValue) { // Going from null to having a value, so increment count _samplerCount++; } System.Windows.Threading.Dispatcher dispatcher = this.Dispatcher; // Release the old value if it is a resource on channel. AddRef the // new value. if (dispatcher != null) { SamplerData? oldSampler = _samplerData[position]; Brush oldBrush = null; if (oldSampler.HasValue) { SamplerData ss = oldSampler.Value; oldBrush = ss._brush; } Brush newBrush = newSampler._brush; DUCE.IResource targetResource = (DUCE.IResource)this; using (CompositionEngineLock.Acquire()) { int channelCount = targetResource.GetChannelCount(); for (int channelIndex = 0; channelIndex < channelCount; channelIndex++) { DUCE.Channel channel = targetResource.GetChannel(channelIndex); Debug.Assert(!channel.IsOutOfBandChannel); Debug.Assert(!targetResource.GetHandle(channel).IsNull); ReleaseResource(oldBrush,channel); AddRefResource(newBrush,channel); } } } _samplerData[position] = newSampler; } /// /// Critical: This code accesses unsafe code blocks /// TreatAsSafe: This code does is safe to call and calling a channel with pointers is ok /// [SecurityCritical,SecurityTreatAsSafe] private void ManualUpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) { // If we're told we can skip the channel check, then we must be on channel Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel)); if (skipOnChannelCheck || _duceResource.IsOnChannel(channel)) { if (PixelShader == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderPixelShaderSet)); } checked { DUCE.MILCMD_SHADEREFFECT data; data.Type = MILCMD.MilCmdShaderEffect; data.Handle = _duceResource.GetHandle(channel); data.TopPadding = _topPadding; data.BottomPadding = _bottomPadding; data.LeftPadding = _leftPadding; data.RightPadding = _rightPadding; data.DdxUvDdyUvRegisterIndex = this.DdxUvDdyUvRegisterIndex; data.hPixelShader = ((DUCE.IResource)PixelShader).GetHandle(channel); unsafe { data.ShaderConstantFloatRegistersSize = (uint)(sizeof(Int16) * _floatCount); data.DependencyPropertyFloatValuesSize = (uint)(4 * sizeof(Single) * _floatCount); data.ShaderSamplerRegistrationInfoSize = (uint)(2 * sizeof(uint) * _samplerCount); // 2 pieces of data per sampler. data.DependencyPropertySamplerValuesSize = (uint)(1 * sizeof(DUCE.ResourceHandle) * _samplerCount); channel.BeginCommand( (byte*)&data, sizeof(DUCE.MILCMD_SHADEREFFECT), (int)(data.ShaderConstantFloatRegistersSize + data.DependencyPropertyFloatValuesSize + data.ShaderSamplerRegistrationInfoSize + data.DependencyPropertySamplerValuesSize ) ); // Arrays appear in this order: // 1) float register indices // 2) float dp values // 3) sampler registration info // 4) sampler dp values // 1) float register indices AppendRegisters(channel, _floatRegisters); // 2) float dp values if (_floatRegisters != null) { for (int i = 0; i < _floatRegisters.Count; i++) { MilColorF? v = _floatRegisters[i]; if (v.HasValue) { MilColorF valueToPush = v.Value; channel.AppendCommandData((byte*)&valueToPush, sizeof(MilColorF)); } } } // 3) sampler registration info if (_samplerCount > 0) { int count = _samplerData.Count; for (int i = 0; i < count; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; // add as a 2-tuple (SamplerRegisterIndex, // SamplingMode) channel.AppendCommandData((byte*)&i, sizeof(int)); int value = (int)(ss._samplingMode); channel.AppendCommandData((byte*)&value, sizeof(int)); } } } // 4) sampler dp values if (_samplerCount > 0) { for (int i = 0; i < _samplerData.Count; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; // Making this assumption by storing a collection of // handles as an Int32Collection Debug.Assert(sizeof(DUCE.ResourceHandle) == sizeof(Int32)); DUCE.ResourceHandle hBrush = ss._brush != null ? ((DUCE.IResource)ss._brush).GetHandle(channel) : DUCE.ResourceHandle.Null; Debug.Assert(!hBrush.IsNull || ss._brush == null, "If brush isn't null, hBrush better not be"); channel.AppendCommandData((byte*)&hBrush, sizeof(DUCE.ResourceHandle)); } } } // That's it... channel.EndCommand(); } } } } // write the non-null values of the list of nullables to the command data. ////// Critical: This code accesses unsafe code blocks /// TreatAsSafe: This code does is safe to call and calling a channel with pointers is ok /// [SecurityCritical,SecurityTreatAsSafe] private void AppendRegisters(DUCE.Channel channel, List list) where T : struct { if (list != null) { unsafe { for (int i = 0; i < list.Count; i++) { T? v = list[i]; if (v.HasValue) { Int16 regIndex = (Int16)i; // put onto stack so next &-operator compiles channel.AppendCommandData((byte*)®Index, sizeof(Int16)); } } } } } // Written by hand to include management of input Brushes (which aren't DPs). internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) { if (_duceResource.CreateOrAddRefOnChannel(channel, System.Windows.Media.Composition.DUCE.ResourceType.TYPE_SHADEREFFECT)) { // Ensures brushes are property instantiated into Duce resources. if (_samplerCount > 0) { int numSamplers = _samplerData.Count; for (int i = 0; i < numSamplers; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; DUCE.IResource brush = ss._brush as DUCE.IResource; if (brush != null) { brush.AddRefOnChannel(channel); } } } } PixelShader vPixelShader = PixelShader; if (vPixelShader != null) ((DUCE.IResource)vPixelShader).AddRefOnChannel(channel); AddRefOnChannelAnimations(channel); UpdateResource(channel, true /* skip "on channel" check - we already know that we're on channel */ ); } return _duceResource.GetHandle(channel); } // Written by hand to include management of input Brushes (which aren't DPs). internal override void ReleaseOnChannelCore(DUCE.Channel channel) { Debug.Assert(_duceResource.IsOnChannel(channel)); if (_duceResource.ReleaseOnChannel(channel)) { // Ensure that brushes are released. if (_samplerCount > 0) { int numSamplers = _samplerData.Count; for (int i = 0; i < numSamplers; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; DUCE.IResource brush = ss._brush as DUCE.IResource; if (brush != null) { brush.ReleaseOnChannel(channel); } } } } PixelShader vPixelShader = PixelShader; if (vPixelShader != null) ((DUCE.IResource)vPixelShader).ReleaseOnChannel(channel); ReleaseOnChannelAnimations(channel); } } // Shader constants can be coerced into 4-tuples of floats only, at this time. // Determine which type the incoming type can go to, if any. internal static Type DetermineShaderConstantType(Type type) { Type result = null; if (type == typeof(double) || type == typeof(float) || type == typeof(Color) || type == typeof(Point) || type == typeof(Size) || type == typeof(Vector) || type == typeof(Point3D) || type == typeof(Vector3D) || type == typeof(Point4D)) { result = typeof(float); } return result; } // Convert to float four tuple internal static void ConvertValueToMilColorF(object value, out MilColorF newVal) { Type t = value.GetType(); // Fill in four-tuples. Always fill in 1.0's for where there are // empty slots, to avoid division by zero on vector operations that // these values are subjected to. // Should order these in terms of most likely to be hit first. if (t == typeof(double) || t == typeof(float)) { float fVal = (t == typeof(double)) ? (float)(double)value : (float)value; // Scalars extend out to fill entire vector. newVal.r = newVal.g = newVal.b = newVal.a = fVal; } else if (t == typeof(Color)) { Color col = (Color)value; newVal.r = (float)col.R / 255f; newVal.g = (float)col.G / 255f; newVal.b = (float)col.B / 255f; newVal.a = (float)col.A / 255f; } else if (t == typeof(Point)) { Point p = (Point)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Size)) { Size s = (Size)value; newVal.r = (float)s.Width; newVal.g = (float)s.Height; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Vector)) { Vector v = (Vector)value; newVal.r = (float)v.X; newVal.g = (float)v.Y; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Point3D)) { Point3D p = (Point3D)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = (float)p.Z; newVal.a = 1f; } else if (t == typeof(Vector3D)) { Vector3D v = (Vector3D)value; newVal.r = (float)v.X; newVal.g = (float)v.Y; newVal.b = (float)v.Z; newVal.a = 1f; } else if (t == typeof(Point4D)) { Point4D p = (Point4D)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = (float)p.Z; newVal.a = (float)p.W; } else { // We should never hit this case, since we check the type using DetermineShaderConstantType // before we call this method. Debug.Assert(false); newVal.r = newVal.b = newVal.g = newVal.a = 1f; } } /// /// Implementation of /// protected override void CloneCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.CloneCore(sourceFreezable); CopyCommon(effect); } ///Freezable.CloneCore . ////// Implementation of /// protected override void CloneCurrentValueCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.CloneCurrentValueCore(sourceFreezable); CopyCommon(effect); } ///Freezable.CloneCurrentValueCore . ////// Implementation of /// protected override void GetAsFrozenCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(effect); } ///Freezable.GetAsFrozenCore . ////// Implementation of /// protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.GetCurrentValueAsFrozenCore(sourceFreezable); CopyCommon(effect); } ///Freezable.GetCurrentValueAsFrozenCore . ////// Clones values that do not have corresponding DPs. /// /// private void CopyCommon(ShaderEffect effect) { _topPadding = effect._topPadding; _bottomPadding = effect._bottomPadding; _leftPadding = effect._leftPadding; _rightPadding = effect._rightPadding; if (_floatRegisters != null) { _floatRegisters = new List(effect._floatRegisters); } if (_samplerData != null) { _samplerData = new List (effect._samplerData); } _floatCount = effect._floatCount; _samplerCount = effect._samplerCount; _ddxUvDdyUvRegisterIndex = effect._ddxUvDdyUvRegisterIndex; _sentFirstTime = effect._sentFirstTime; } private struct SamplerData { public Brush _brush; public SamplingMode _samplingMode; } private const SamplingMode _defaultSamplingMode = SamplingMode.Auto; // Instance data private double _topPadding = 0.0; private double _bottomPadding = 0.0; private double _leftPadding = 0.0; private double _rightPadding = 0.0; private List _floatRegisters = null; private List _samplerData = null; private int _floatCount = 0; private int _samplerCount = 0; private int _ddxUvDdyUvRegisterIndex = -1; private bool _sentFirstTime = false; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Microsoft Windows Presentation Foundation // Copyright (c) Microsoft Corporation, 2008 // // File: ShaderEffect.cs //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Media; using System.IO; using System.Windows.Markup; using System.Windows.Media.Composition; using System.Windows.Media.Media3D; using System.Security; using System.Security.Permissions; using System.Runtime.InteropServices; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Media.Effects { public abstract partial class ShaderEffect : Effect { /// /// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingTop { get { ReadPreamble(); return _topPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingTop", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _topPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingBottom { get { ReadPreamble(); return _bottomPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingBottom", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _bottomPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingLeft { get { ReadPreamble(); return _leftPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingLeft", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _leftPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// Padding is used to specify that an effect's output texture is larger than its input // texture in a specific direction, e.g. for a drop shadow effect. /// protected double PaddingRight { get { ReadPreamble(); return _rightPadding; } set { WritePreamble(); if (value < 0.0) { throw new ArgumentOutOfRangeException("PaddingRight", value, SR.Get(SRID.Effect_ShaderEffectPadding)); } else { _rightPadding = value; RegisterForAsyncUpdateResource(); } WritePostscript(); } } ////// To specify a shader constant register to set to the size of the /// destination. Default is -1, which means to not send any. Only /// intended to be set once, in the constructor, and will fail if set /// after the effect is initially processed. /// protected int DdxUvDdyUvRegisterIndex { get { ReadPreamble(); return _ddxUvDdyUvRegisterIndex; } set { WritePreamble(); if (_sentFirstTime) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderDdxUvDdyUvRegisterIndex)); } _ddxUvDdyUvRegisterIndex = value; WritePostscript(); } } ////// Tells the Effect that the shader constant or sampler corresponding /// to the specified DependencyProperty needs to be updated. /// protected void UpdateShaderValue(DependencyProperty dp) { if (dp != null) { WritePreamble(); object val = this.GetValue(dp); var metadata = dp.GetMetadata(this); if (metadata != null) { var callback = metadata.PropertyChangedCallback; if (callback != null) { callback(this, new DependencyPropertyChangedEventArgs(dp, val, val)); } } WritePostscript(); } } ////// Construct a PropertyChangedCallback which, when invoked, will result in the DP being /// associated with the specified shader constant register index. /// protected static PropertyChangedCallback PixelShaderConstantCallback(int floatRegisterIndex) { return (obj, args) => { ShaderEffect eff = obj as ShaderEffect; if (eff != null) { eff.UpdateShaderConstant(args.Property, args.NewValue, floatRegisterIndex); } }; } ////// Construct a PropertyChangedCallback which, when invoked, will result /// in the DP being associated with the specified shader sampler /// register index. Expected to be called on a Brush-valued /// DependencyProperty. /// protected static PropertyChangedCallback PixelShaderSamplerCallback(int samplerRegisterIndex) { return PixelShaderSamplerCallback(samplerRegisterIndex, _defaultSamplingMode); } ////// Construct a PropertyChangedCallback which, when invoked, will result /// in the DP being associated with the specified shader sampler /// register index. Expected to be called on a Brush-valued /// DependencyProperty. /// protected static PropertyChangedCallback PixelShaderSamplerCallback(int samplerRegisterIndex, SamplingMode samplingMode) { return (obj, args) => { ShaderEffect eff = obj as ShaderEffect; if (eff != null) { if (args.IsAValueChange) { eff.UpdateShaderSampler(args.Property, args.NewValue, samplerRegisterIndex, samplingMode); } } }; } ////// Helper for defining Brush-valued DependencyProperties to associate with a /// sampler register in the PixelShader. /// protected static DependencyProperty RegisterPixelShaderSamplerProperty(string dpName, Type ownerType, int samplerRegisterIndex) { return RegisterPixelShaderSamplerProperty(dpName, ownerType, samplerRegisterIndex, _defaultSamplingMode); } ////// Helper for defining Brush-valued DependencyProperties to associate with a /// sampler register in the PixelShader. /// protected static DependencyProperty RegisterPixelShaderSamplerProperty(string dpName, Type ownerType, int samplerRegisterIndex, SamplingMode samplingMode) { return DependencyProperty.Register(dpName, typeof(Brush), ownerType, new UIPropertyMetadata(Effect.ImplicitInput, PixelShaderSamplerCallback(samplerRegisterIndex, samplingMode))); } // Updates the shader constant referred to by the DP. Converts to the // form that the HLSL shaders want, and stores that value, since it will // be sent on every update. // We WritePreamble/Postscript here since this method is called by the user with the callback // created in PixelShaderConstantCallback. private void UpdateShaderConstant(DependencyProperty dp, object newValue, int registerIndex) { WritePreamble(); Type t = DetermineShaderConstantType(dp.PropertyType); if (t == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderConstantType, dp.PropertyType.Name)); } else { int registerMax = 32; if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(SRID.Effect_ShaderConstantRegisterLimit), "dp"); } if (t == typeof(float)) { MilColorF fourTuple; ConvertValueToMilColorF(newValue, out fourTuple); StashInPosition(ref _floatRegisters, registerIndex, fourTuple, 32, ref _floatCount); } else { // We should convert all acceptable types to float. Debug.Assert(false); } } // Propagate dirty this.PropertyChanged(dp); WritePostscript(); } // Updates the shader sampler referred to by the DP. Converts to the // form that the HLSL shaders want, and stores that value, since it will // be sent on every update. // We WritePreamble/Postscript here since this method is called by the user with the callback // created in PixelShaderSamplerCallback. private void UpdateShaderSampler(DependencyProperty dp, object newValue, int registerIndex, SamplingMode samplingMode) { WritePreamble(); if (newValue != null) { if (!(typeof(VisualBrush).IsInstanceOfType(newValue) || typeof(ImplicitInputBrush).IsInstanceOfType(newValue) || typeof(ImageBrush).IsInstanceOfType(newValue)) ) { // Note that if the type of the brush is ImplicitInputBrush and the value is non null, the value is actually // Effect.ImplicitInput. This is because ImplicitInputBrush is internal and the user can only get to the singleton // Effect.ImplicitInput. throw new ArgumentException(SR.Get(SRID.Effect_ShaderSamplerType), "dp"); } } // PS2.0 allows max 16, but some cards seem to have trouble with 16 samplers being set. // Restricting to 4 for now. if (registerIndex >= 4 || registerIndex < 0) // allow -1 for default { throw new ArgumentException(SR.Get(SRID.Effect_ShaderSamplerRegisterLimit)); } SamplerData sd = new SamplerData() { _brush = (Brush)newValue, _samplingMode = samplingMode }; StashSamplerDataInPosition(registerIndex, sd, 16); // Propagate dirty this.PropertyChanged(dp); WritePostscript(); } // Ensures that list is extended to 'position', and that // the specified value is inserted there. For lists of value types. private static void StashInPosition(ref List list, int position, T value, int maxIndex, ref int count) where T : struct { if (list == null) { list = new List (maxIndex); } if (list.Count <= position) { int numToAdd = position - list.Count + 1; for (int i = 0; i < numToAdd; i++) { list.Add((T?)null); } } if (!list[position].HasValue) { // Going from null to having a value, so increment count count++; } list[position] = value; } // Ensures that _samplerData is extended to 'position', and that // the specified value is inserted there. private void StashSamplerDataInPosition(int position, SamplerData newSampler, int maxIndex) { if (_samplerData == null) { _samplerData = new List (maxIndex); } if (_samplerData.Count <= position) { int numToAdd = position - _samplerData.Count + 1; for (int i = 0; i < numToAdd; i++) { _samplerData.Add((SamplerData?)null); } } if (!_samplerData[position].HasValue) { // Going from null to having a value, so increment count _samplerCount++; } System.Windows.Threading.Dispatcher dispatcher = this.Dispatcher; // Release the old value if it is a resource on channel. AddRef the // new value. if (dispatcher != null) { SamplerData? oldSampler = _samplerData[position]; Brush oldBrush = null; if (oldSampler.HasValue) { SamplerData ss = oldSampler.Value; oldBrush = ss._brush; } Brush newBrush = newSampler._brush; DUCE.IResource targetResource = (DUCE.IResource)this; using (CompositionEngineLock.Acquire()) { int channelCount = targetResource.GetChannelCount(); for (int channelIndex = 0; channelIndex < channelCount; channelIndex++) { DUCE.Channel channel = targetResource.GetChannel(channelIndex); Debug.Assert(!channel.IsOutOfBandChannel); Debug.Assert(!targetResource.GetHandle(channel).IsNull); ReleaseResource(oldBrush,channel); AddRefResource(newBrush,channel); } } } _samplerData[position] = newSampler; } /// /// Critical: This code accesses unsafe code blocks /// TreatAsSafe: This code does is safe to call and calling a channel with pointers is ok /// [SecurityCritical,SecurityTreatAsSafe] private void ManualUpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) { // If we're told we can skip the channel check, then we must be on channel Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel)); if (skipOnChannelCheck || _duceResource.IsOnChannel(channel)) { if (PixelShader == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderPixelShaderSet)); } checked { DUCE.MILCMD_SHADEREFFECT data; data.Type = MILCMD.MilCmdShaderEffect; data.Handle = _duceResource.GetHandle(channel); data.TopPadding = _topPadding; data.BottomPadding = _bottomPadding; data.LeftPadding = _leftPadding; data.RightPadding = _rightPadding; data.DdxUvDdyUvRegisterIndex = this.DdxUvDdyUvRegisterIndex; data.hPixelShader = ((DUCE.IResource)PixelShader).GetHandle(channel); unsafe { data.ShaderConstantFloatRegistersSize = (uint)(sizeof(Int16) * _floatCount); data.DependencyPropertyFloatValuesSize = (uint)(4 * sizeof(Single) * _floatCount); data.ShaderSamplerRegistrationInfoSize = (uint)(2 * sizeof(uint) * _samplerCount); // 2 pieces of data per sampler. data.DependencyPropertySamplerValuesSize = (uint)(1 * sizeof(DUCE.ResourceHandle) * _samplerCount); channel.BeginCommand( (byte*)&data, sizeof(DUCE.MILCMD_SHADEREFFECT), (int)(data.ShaderConstantFloatRegistersSize + data.DependencyPropertyFloatValuesSize + data.ShaderSamplerRegistrationInfoSize + data.DependencyPropertySamplerValuesSize ) ); // Arrays appear in this order: // 1) float register indices // 2) float dp values // 3) sampler registration info // 4) sampler dp values // 1) float register indices AppendRegisters(channel, _floatRegisters); // 2) float dp values if (_floatRegisters != null) { for (int i = 0; i < _floatRegisters.Count; i++) { MilColorF? v = _floatRegisters[i]; if (v.HasValue) { MilColorF valueToPush = v.Value; channel.AppendCommandData((byte*)&valueToPush, sizeof(MilColorF)); } } } // 3) sampler registration info if (_samplerCount > 0) { int count = _samplerData.Count; for (int i = 0; i < count; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; // add as a 2-tuple (SamplerRegisterIndex, // SamplingMode) channel.AppendCommandData((byte*)&i, sizeof(int)); int value = (int)(ss._samplingMode); channel.AppendCommandData((byte*)&value, sizeof(int)); } } } // 4) sampler dp values if (_samplerCount > 0) { for (int i = 0; i < _samplerData.Count; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; // Making this assumption by storing a collection of // handles as an Int32Collection Debug.Assert(sizeof(DUCE.ResourceHandle) == sizeof(Int32)); DUCE.ResourceHandle hBrush = ss._brush != null ? ((DUCE.IResource)ss._brush).GetHandle(channel) : DUCE.ResourceHandle.Null; Debug.Assert(!hBrush.IsNull || ss._brush == null, "If brush isn't null, hBrush better not be"); channel.AppendCommandData((byte*)&hBrush, sizeof(DUCE.ResourceHandle)); } } } // That's it... channel.EndCommand(); } } } } // write the non-null values of the list of nullables to the command data. ////// Critical: This code accesses unsafe code blocks /// TreatAsSafe: This code does is safe to call and calling a channel with pointers is ok /// [SecurityCritical,SecurityTreatAsSafe] private void AppendRegisters(DUCE.Channel channel, List list) where T : struct { if (list != null) { unsafe { for (int i = 0; i < list.Count; i++) { T? v = list[i]; if (v.HasValue) { Int16 regIndex = (Int16)i; // put onto stack so next &-operator compiles channel.AppendCommandData((byte*)®Index, sizeof(Int16)); } } } } } // Written by hand to include management of input Brushes (which aren't DPs). internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) { if (_duceResource.CreateOrAddRefOnChannel(channel, System.Windows.Media.Composition.DUCE.ResourceType.TYPE_SHADEREFFECT)) { // Ensures brushes are property instantiated into Duce resources. if (_samplerCount > 0) { int numSamplers = _samplerData.Count; for (int i = 0; i < numSamplers; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; DUCE.IResource brush = ss._brush as DUCE.IResource; if (brush != null) { brush.AddRefOnChannel(channel); } } } } PixelShader vPixelShader = PixelShader; if (vPixelShader != null) ((DUCE.IResource)vPixelShader).AddRefOnChannel(channel); AddRefOnChannelAnimations(channel); UpdateResource(channel, true /* skip "on channel" check - we already know that we're on channel */ ); } return _duceResource.GetHandle(channel); } // Written by hand to include management of input Brushes (which aren't DPs). internal override void ReleaseOnChannelCore(DUCE.Channel channel) { Debug.Assert(_duceResource.IsOnChannel(channel)); if (_duceResource.ReleaseOnChannel(channel)) { // Ensure that brushes are released. if (_samplerCount > 0) { int numSamplers = _samplerData.Count; for (int i = 0; i < numSamplers; i++) { SamplerData? ssn = _samplerData[i]; if (ssn.HasValue) { SamplerData ss = ssn.Value; DUCE.IResource brush = ss._brush as DUCE.IResource; if (brush != null) { brush.ReleaseOnChannel(channel); } } } } PixelShader vPixelShader = PixelShader; if (vPixelShader != null) ((DUCE.IResource)vPixelShader).ReleaseOnChannel(channel); ReleaseOnChannelAnimations(channel); } } // Shader constants can be coerced into 4-tuples of floats only, at this time. // Determine which type the incoming type can go to, if any. internal static Type DetermineShaderConstantType(Type type) { Type result = null; if (type == typeof(double) || type == typeof(float) || type == typeof(Color) || type == typeof(Point) || type == typeof(Size) || type == typeof(Vector) || type == typeof(Point3D) || type == typeof(Vector3D) || type == typeof(Point4D)) { result = typeof(float); } return result; } // Convert to float four tuple internal static void ConvertValueToMilColorF(object value, out MilColorF newVal) { Type t = value.GetType(); // Fill in four-tuples. Always fill in 1.0's for where there are // empty slots, to avoid division by zero on vector operations that // these values are subjected to. // Should order these in terms of most likely to be hit first. if (t == typeof(double) || t == typeof(float)) { float fVal = (t == typeof(double)) ? (float)(double)value : (float)value; // Scalars extend out to fill entire vector. newVal.r = newVal.g = newVal.b = newVal.a = fVal; } else if (t == typeof(Color)) { Color col = (Color)value; newVal.r = (float)col.R / 255f; newVal.g = (float)col.G / 255f; newVal.b = (float)col.B / 255f; newVal.a = (float)col.A / 255f; } else if (t == typeof(Point)) { Point p = (Point)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Size)) { Size s = (Size)value; newVal.r = (float)s.Width; newVal.g = (float)s.Height; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Vector)) { Vector v = (Vector)value; newVal.r = (float)v.X; newVal.g = (float)v.Y; newVal.b = 1f; newVal.a = 1f; } else if (t == typeof(Point3D)) { Point3D p = (Point3D)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = (float)p.Z; newVal.a = 1f; } else if (t == typeof(Vector3D)) { Vector3D v = (Vector3D)value; newVal.r = (float)v.X; newVal.g = (float)v.Y; newVal.b = (float)v.Z; newVal.a = 1f; } else if (t == typeof(Point4D)) { Point4D p = (Point4D)value; newVal.r = (float)p.X; newVal.g = (float)p.Y; newVal.b = (float)p.Z; newVal.a = (float)p.W; } else { // We should never hit this case, since we check the type using DetermineShaderConstantType // before we call this method. Debug.Assert(false); newVal.r = newVal.b = newVal.g = newVal.a = 1f; } } /// /// Implementation of /// protected override void CloneCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.CloneCore(sourceFreezable); CopyCommon(effect); } ///Freezable.CloneCore . ////// Implementation of /// protected override void CloneCurrentValueCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.CloneCurrentValueCore(sourceFreezable); CopyCommon(effect); } ///Freezable.CloneCurrentValueCore . ////// Implementation of /// protected override void GetAsFrozenCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(effect); } ///Freezable.GetAsFrozenCore . ////// Implementation of /// protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) { ShaderEffect effect = (ShaderEffect)sourceFreezable; base.GetCurrentValueAsFrozenCore(sourceFreezable); CopyCommon(effect); } ///Freezable.GetCurrentValueAsFrozenCore . ////// Clones values that do not have corresponding DPs. /// /// private void CopyCommon(ShaderEffect effect) { _topPadding = effect._topPadding; _bottomPadding = effect._bottomPadding; _leftPadding = effect._leftPadding; _rightPadding = effect._rightPadding; if (_floatRegisters != null) { _floatRegisters = new List(effect._floatRegisters); } if (_samplerData != null) { _samplerData = new List (effect._samplerData); } _floatCount = effect._floatCount; _samplerCount = effect._samplerCount; _ddxUvDdyUvRegisterIndex = effect._ddxUvDdyUvRegisterIndex; _sentFirstTime = effect._sentFirstTime; } private struct SamplerData { public Brush _brush; public SamplingMode _samplingMode; } private const SamplingMode _defaultSamplingMode = SamplingMode.Auto; // Instance data private double _topPadding = 0.0; private double _bottomPadding = 0.0; private double _leftPadding = 0.0; private double _rightPadding = 0.0; private List _floatRegisters = null; private List _samplerData = null; private int _floatCount = 0; private int _samplerCount = 0; private int _ddxUvDdyUvRegisterIndex = -1; private bool _sentFirstTime = false; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebPartManager.cs
- TableDetailsCollection.cs
- PaperSource.cs
- DynamicAttribute.cs
- CollectionBase.cs
- GridViewColumnCollectionChangedEventArgs.cs
- FixedTextPointer.cs
- ValueUtilsSmi.cs
- XmlEncodedRawTextWriter.cs
- IteratorFilter.cs
- CompositeScriptReference.cs
- XMLDiffLoader.cs
- EntityDataSourceContextCreatingEventArgs.cs
- _FixedSizeReader.cs
- HtmlGenericControl.cs
- Themes.cs
- SocketManager.cs
- cookie.cs
- KoreanCalendar.cs
- assertwrapper.cs
- ImplicitInputBrush.cs
- XmlObjectSerializerWriteContext.cs
- UnsafeNativeMethods.cs
- SqlSupersetValidator.cs
- FormViewInsertEventArgs.cs
- ListSortDescription.cs
- PaperSource.cs
- PersonalizationProvider.cs
- ProcessThreadDesigner.cs
- cookieexception.cs
- MimeParameterWriter.cs
- PageParser.cs
- ResourceProperty.cs
- MemoryPressure.cs
- ForeignKeyConstraint.cs
- TypeListConverter.cs
- __Filters.cs
- SamlSubjectStatement.cs
- FacetEnabledSchemaElement.cs
- MobileUITypeEditor.cs
- AssemblyBuilderData.cs
- AttributeProviderAttribute.cs
- FocusManager.cs
- InputLangChangeEvent.cs
- MailHeaderInfo.cs
- TaskbarItemInfo.cs
- PageCatalogPartDesigner.cs
- ComNativeDescriptor.cs
- LinearKeyFrames.cs
- SelectorItemAutomationPeer.cs
- WorkflowServiceAttributes.cs
- WmfPlaceableFileHeader.cs
- ProfileGroupSettingsCollection.cs
- TextTreeUndo.cs
- ListBoxItemAutomationPeer.cs
- DependentList.cs
- CurrentChangingEventArgs.cs
- DesignerForm.cs
- CommandField.cs
- ADMembershipUser.cs
- DSASignatureDeformatter.cs
- StringExpressionSet.cs
- MouseBinding.cs
- WebControl.cs
- StatusBarItem.cs
- DispatchChannelSink.cs
- CustomTypeDescriptor.cs
- FileChangesMonitor.cs
- ReadOnlyDataSource.cs
- BaseDataBoundControl.cs
- SortFieldComparer.cs
- LessThanOrEqual.cs
- BorderGapMaskConverter.cs
- CompilerTypeWithParams.cs
- BooleanToVisibilityConverter.cs
- DBDataPermissionAttribute.cs
- InvalidProgramException.cs
- XmlRootAttribute.cs
- ISAPIWorkerRequest.cs
- SafeHandles.cs
- ClientTargetCollection.cs
- XmlUnspecifiedAttribute.cs
- QuotedStringFormatReader.cs
- XamlInt32CollectionSerializer.cs
- Range.cs
- LocalFileSettingsProvider.cs
- DataRow.cs
- NameSpaceEvent.cs
- AnimationClockResource.cs
- ProgressBar.cs
- EmptyEnumerator.cs
- LineSegment.cs
- _AutoWebProxyScriptWrapper.cs
- AtomicFile.cs
- ControlBuilderAttribute.cs
- Size3D.cs
- DataSysAttribute.cs
- HttpContext.cs
- PartialCachingAttribute.cs
- XmlMapping.cs