Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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
- CustomBindingCollectionElement.cs
- ObjectAnimationUsingKeyFrames.cs
- DependencyPropertyChangedEventArgs.cs
- HandlerFactoryWrapper.cs
- LostFocusEventManager.cs
- BitmapEffectState.cs
- HttpChannelHelper.cs
- ScriptServiceAttribute.cs
- FormView.cs
- AggregateNode.cs
- MetadataReference.cs
- CustomErrorsSection.cs
- TaiwanLunisolarCalendar.cs
- DrawingGroup.cs
- AbstractSvcMapFileLoader.cs
- DbDataReader.cs
- InkCanvasSelectionAdorner.cs
- IsolatedStoragePermission.cs
- DecimalKeyFrameCollection.cs
- ProvideValueServiceProvider.cs
- ExpressionPrinter.cs
- ClrProviderManifest.cs
- CommandConverter.cs
- ActivityExecutor.cs
- HtmlElement.cs
- TableCellAutomationPeer.cs
- InfoCardArgumentException.cs
- TableCell.cs
- DataGridViewBindingCompleteEventArgs.cs
- LinqDataSourceSelectEventArgs.cs
- ImageBrush.cs
- XsdCachingReader.cs
- SimpleParser.cs
- PhonemeEventArgs.cs
- AuthorizationSection.cs
- counter.cs
- HttpCookieCollection.cs
- GraphicsPath.cs
- securitymgrsite.cs
- ThreadExceptionEvent.cs
- PreviewPageInfo.cs
- VarRemapper.cs
- View.cs
- StreamProxy.cs
- MimeMultiPart.cs
- PathSegment.cs
- GotoExpression.cs
- HttpCookieCollection.cs
- SqlRewriteScalarSubqueries.cs
- MailWebEventProvider.cs
- SerializationAttributes.cs
- Publisher.cs
- SmtpNtlmAuthenticationModule.cs
- CollectionEditorDialog.cs
- DrawingContextDrawingContextWalker.cs
- SqlWebEventProvider.cs
- ConfigurationException.cs
- BigInt.cs
- Debug.cs
- MenuItem.cs
- XmlSchemaSimpleContentExtension.cs
- WebPartConnectionsConnectVerb.cs
- TdsParameterSetter.cs
- XmlIlTypeHelper.cs
- XmlElementAttribute.cs
- HostedAspNetEnvironment.cs
- NegationPusher.cs
- XmlStringTable.cs
- BinaryParser.cs
- SoapBinding.cs
- KeyBinding.cs
- RegexParser.cs
- ScopedMessagePartSpecification.cs
- TokenBasedSet.cs
- ColumnResizeUndoUnit.cs
- DataSourceSelectArguments.cs
- FontStyleConverter.cs
- ProviderUtil.cs
- XmlNode.cs
- ISCIIEncoding.cs
- ReferenceService.cs
- LicenseContext.cs
- SQLMoney.cs
- PathFigureCollectionValueSerializer.cs
- Application.cs
- HtmlWindowCollection.cs
- NamedPipeConnectionPoolSettings.cs
- HMACSHA512.cs
- Cursor.cs
- sqlnorm.cs
- Options.cs
- VoiceObjectToken.cs
- WindowShowOrOpenTracker.cs
- PerformanceCounterPermission.cs
- SecurityException.cs
- LinearKeyFrames.cs
- UriWriter.cs
- DataObject.cs
- ScrollItemProviderWrapper.cs
- GridView.cs