Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / Effects / ShaderEffect.cs / 1305600 / 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 { ////// Takes in content bounds, and returns the bounds of the rendered /// output of that content after the Effect is applied. /// internal override Rect GetRenderBounds(Rect contentBounds) { Point topLeft = new Point(); Point bottomRight = new Point(); topLeft.X = contentBounds.TopLeft.X - PaddingLeft; topLeft.Y = contentBounds.TopLeft.Y - PaddingTop; bottomRight.X = contentBounds.BottomRight.X + PaddingRight; bottomRight.Y = contentBounds.BottomRight.Y + PaddingBottom; return new Rect(topLeft, bottomRight); } ////// 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("value", 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("value", 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("value", 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("value", 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(); _ddxUvDdyUvRegisterIndex = value; WritePostscript(); } } ////// This method is invoked whenever the PixelShader property changes. /// private void PixelShaderPropertyChangedHook(DependencyPropertyChangedEventArgs e) { PixelShader oldShader = (PixelShader)e.OldValue; if (oldShader != null) { oldShader._shaderBytecodeChanged -= OnPixelShaderBytecodeChanged; } PixelShader newShader = (PixelShader)e.NewValue; if (newShader != null) { newShader._shaderBytecodeChanged += OnPixelShaderBytecodeChanged; } OnPixelShaderBytecodeChanged(PixelShader, null); } ////// When the PixelShader's bytecode changes to a ps_2_0 shader, verify that registers only /// available in ps_3_0 are not being used. /// private void OnPixelShaderBytecodeChanged(object sender, EventArgs e) { PixelShader pixelShader = (PixelShader)sender; if (pixelShader != null && pixelShader.ShaderMajorVersion == 2 && pixelShader.ShaderMinorVersion == 0 && UsesPS30OnlyRegisters()) { throw new InvalidOperationException(SR.Get(SRID.Effect_20ShaderUsing30Registers)); } } private bool UsesPS30OnlyRegisters() { // int and bool registers are ps_3_0 only if (_intCount > 0 || _intRegisters != null || _boolCount > 0 || _boolRegisters != null) { return true; } // float registers 32 or above are ps_3_0 only if (_floatRegisters != null) { for (int i = PS_2_0_FLOAT_REGISTER_LIMIT; i < _floatRegisters.Count; i++) { if (_floatRegisters[i] != null) { return true; } } } // sampler registers 4 or above are ps_3_0 only // Note: it's really 16, but we use 4 because some cards have trouble with 16 samplers // being set. if (_samplerData != null) { for (int i = PS_2_0_SAMPLER_LIMIT; i < _samplerData.Count; i++) { if (_samplerData[i] != null) { return true; } } } return false; } ////// 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, PixelShader); if (t == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderConstantType, dp.PropertyType.Name)); } else { // // Treat as a float constant in ps_2_0 by default // int registerMax = PS_2_0_FLOAT_REGISTER_LIMIT; string srid = SRID.Effect_Shader20ConstantRegisterLimit; if (PixelShader != null && PixelShader.ShaderMajorVersion >= 3) { // // If there's a ps_3_0 shader, the limit depends on the type // if (t == typeof(float)) { registerMax = PS_3_0_FLOAT_REGISTER_LIMIT; srid = SRID.Effect_Shader30FloatConstantRegisterLimit; } else if (t == typeof(int)) { registerMax = PS_3_0_INT_REGISTER_LIMIT; srid = SRID.Effect_Shader30IntConstantRegisterLimit; } else if (t == typeof(bool)) { registerMax = PS_3_0_BOOL_REGISTER_LIMIT; srid = SRID.Effect_Shader30BoolConstantRegisterLimit; } } if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(srid), "dp"); } if (t == typeof(float)) { MilColorF fourTuple; ConvertValueToMilColorF(newValue, out fourTuple); StashInPosition(ref _floatRegisters, registerIndex, fourTuple, registerMax, ref _floatCount); } else if (t == typeof(int)) { MilColorI fourTuple; ConvertValueToMilColorI(newValue, out fourTuple); StashInPosition(ref _intRegisters, registerIndex, fourTuple, registerMax, ref _intCount); } else if (t == typeof(bool)) { StashInPosition(ref _boolRegisters, registerIndex, (bool)newValue, registerMax, ref _boolCount); } else { // We should have converted all acceptable types. 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(BitmapCacheBrush).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"); } } // // Treat as ps_2_0 by default // int registerMax = PS_2_0_SAMPLER_LIMIT; string srid = SRID.Effect_Shader20SamplerRegisterLimit; if (PixelShader != null && PixelShader.ShaderMajorVersion >= 3) { registerMax = PS_3_0_SAMPLER_LIMIT; srid = SRID.Effect_Shader30SamplerRegisterLimit; } if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(srid)); } SamplerData sd = new SamplerData() { _brush = (Brush)newValue, _samplingMode = samplingMode }; StashSamplerDataInPosition(registerIndex, sd, registerMax); // 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 uint 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.ShaderConstantIntRegistersSize = (uint)(sizeof(Int16) * _intCount); data.DependencyPropertyIntValuesSize = (uint)(4 * sizeof(Int32) * _intCount); data.ShaderConstantBoolRegistersSize = (uint)(sizeof(Int16) * _boolCount); // // Note: the multiply by 4 is not because the boolean register holds 4 // values, but to compensate for the difference between sizeof(bool) // in managed code (1) and sizeof(BOOL) in native code (4). // data.DependencyPropertyBoolValuesSize = (uint)(4 * sizeof(bool) * _boolCount); 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.ShaderConstantIntRegistersSize + data.DependencyPropertyIntValuesSize + data.ShaderConstantBoolRegistersSize + data.DependencyPropertyBoolValuesSize + data.ShaderSamplerRegistrationInfoSize + data.DependencyPropertySamplerValuesSize ) ); // Arrays appear in this order: // 1) float register indices // 2) float dp values // 3) int register indices // 4) int dp values // 5) bool register indices // 6) bool dp values // 7) sampler registration info // 8) 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) int register indices AppendRegisters(channel, _intRegisters); // 4) int dp values if (_intRegisters != null) { for (int i = 0; i < _intRegisters.Count; i++) { MilColorI? v = _intRegisters[i]; if (v.HasValue) { MilColorI valueToPush = v.Value; channel.AppendCommandData((byte*)&valueToPush, sizeof(MilColorI)); } } } // 5) bool register indices AppendRegisters(channel, _boolRegisters); // 6) bool dp values if (_boolRegisters != null) { for (int i = 0; i < _boolRegisters.Count; i++) { bool? v = _boolRegisters[i]; if (v.HasValue) { // // Note: need 4 bytes for the bool, because the render thread // unmarshals it into a 4-byte BOOL. See the comment above for // DependencyPropertyBoolValuesSize for more details. // Int32 valueToPush = v.Value ? 1 : 0; channel.AppendCommandData((byte*)&valueToPush, sizeof(Int32)); } } } // 7) 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)); } } } // 8) 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(this, 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 in ps_2_0. Ints and bools are // also supported in ps_3_0. internal static Type DetermineShaderConstantType(Type type, PixelShader pixelShader) { 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); } else if (pixelShader != null && pixelShader.ShaderMajorVersion >= 3) { // // int and bool are also supported by ps_3_0. // if (type == typeof(int) || type == typeof(uint) || type == typeof(byte) || type == typeof(sbyte) || type == typeof(long) || type == typeof(ulong) || type == typeof(short) || type == typeof(ushort) || type == typeof(char)) { result = typeof(int); } else if (type == typeof(bool)) { result = typeof(bool); } } 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; } } // Convert to int four tuple internal static void ConvertValueToMilColorI(object value, out MilColorI newVal) { Type t = value.GetType(); // Fill in four-tuples. Always fill in 1's for where there are // empty slots, to avoid division by zero on vector operations that // these values are subjected to. int iVal = 1; // // Note: conversions from long/ulong/uint can change the sign of the number // if (t == typeof(long)) { iVal = (int)(long)value; } else if (t == typeof(ulong)) { iVal = (int)(ulong)value; } else if (t == typeof(uint)) { iVal = (int)(uint)value; } else if (t == typeof(short)) { iVal = (int)(short)value; } else if (t == typeof(ushort)) { iVal = (int)(ushort)value; } else if (t == typeof(byte)) { iVal = (int)(byte)value; } else if (t == typeof(sbyte)) { iVal = (int)(sbyte)value; } else if (t == typeof(char)) { iVal = (int)(char)value; } else { iVal = (int)value; } // Scalars extend out to fill entire vector. newVal.r = newVal.g = newVal.b = newVal.a = iVal; } /// /// 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; } 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 _intRegisters = null; private List _boolRegisters = null; private List _samplerData = null; private uint _floatCount = 0; private uint _intCount = 0; private uint _boolCount = 0; private uint _samplerCount = 0; private int _ddxUvDdyUvRegisterIndex = -1; private const int PS_2_0_FLOAT_REGISTER_LIMIT = 32; private const int PS_3_0_FLOAT_REGISTER_LIMIT = 224; private const int PS_3_0_INT_REGISTER_LIMIT = 16; private const int PS_3_0_BOOL_REGISTER_LIMIT = 16; // ps_2_0 allows max 16, but some cards seem to have trouble with 16 samplers being set. // Restricting to 4 for now. private const int PS_2_0_SAMPLER_LIMIT = 4; private const int PS_3_0_SAMPLER_LIMIT = 8; } } // 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 { /// /// Takes in content bounds, and returns the bounds of the rendered /// output of that content after the Effect is applied. /// internal override Rect GetRenderBounds(Rect contentBounds) { Point topLeft = new Point(); Point bottomRight = new Point(); topLeft.X = contentBounds.TopLeft.X - PaddingLeft; topLeft.Y = contentBounds.TopLeft.Y - PaddingTop; bottomRight.X = contentBounds.BottomRight.X + PaddingRight; bottomRight.Y = contentBounds.BottomRight.Y + PaddingBottom; return new Rect(topLeft, bottomRight); } ////// 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("value", 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("value", 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("value", 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("value", 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(); _ddxUvDdyUvRegisterIndex = value; WritePostscript(); } } ////// This method is invoked whenever the PixelShader property changes. /// private void PixelShaderPropertyChangedHook(DependencyPropertyChangedEventArgs e) { PixelShader oldShader = (PixelShader)e.OldValue; if (oldShader != null) { oldShader._shaderBytecodeChanged -= OnPixelShaderBytecodeChanged; } PixelShader newShader = (PixelShader)e.NewValue; if (newShader != null) { newShader._shaderBytecodeChanged += OnPixelShaderBytecodeChanged; } OnPixelShaderBytecodeChanged(PixelShader, null); } ////// When the PixelShader's bytecode changes to a ps_2_0 shader, verify that registers only /// available in ps_3_0 are not being used. /// private void OnPixelShaderBytecodeChanged(object sender, EventArgs e) { PixelShader pixelShader = (PixelShader)sender; if (pixelShader != null && pixelShader.ShaderMajorVersion == 2 && pixelShader.ShaderMinorVersion == 0 && UsesPS30OnlyRegisters()) { throw new InvalidOperationException(SR.Get(SRID.Effect_20ShaderUsing30Registers)); } } private bool UsesPS30OnlyRegisters() { // int and bool registers are ps_3_0 only if (_intCount > 0 || _intRegisters != null || _boolCount > 0 || _boolRegisters != null) { return true; } // float registers 32 or above are ps_3_0 only if (_floatRegisters != null) { for (int i = PS_2_0_FLOAT_REGISTER_LIMIT; i < _floatRegisters.Count; i++) { if (_floatRegisters[i] != null) { return true; } } } // sampler registers 4 or above are ps_3_0 only // Note: it's really 16, but we use 4 because some cards have trouble with 16 samplers // being set. if (_samplerData != null) { for (int i = PS_2_0_SAMPLER_LIMIT; i < _samplerData.Count; i++) { if (_samplerData[i] != null) { return true; } } } return false; } ////// 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, PixelShader); if (t == null) { throw new InvalidOperationException(SR.Get(SRID.Effect_ShaderConstantType, dp.PropertyType.Name)); } else { // // Treat as a float constant in ps_2_0 by default // int registerMax = PS_2_0_FLOAT_REGISTER_LIMIT; string srid = SRID.Effect_Shader20ConstantRegisterLimit; if (PixelShader != null && PixelShader.ShaderMajorVersion >= 3) { // // If there's a ps_3_0 shader, the limit depends on the type // if (t == typeof(float)) { registerMax = PS_3_0_FLOAT_REGISTER_LIMIT; srid = SRID.Effect_Shader30FloatConstantRegisterLimit; } else if (t == typeof(int)) { registerMax = PS_3_0_INT_REGISTER_LIMIT; srid = SRID.Effect_Shader30IntConstantRegisterLimit; } else if (t == typeof(bool)) { registerMax = PS_3_0_BOOL_REGISTER_LIMIT; srid = SRID.Effect_Shader30BoolConstantRegisterLimit; } } if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(srid), "dp"); } if (t == typeof(float)) { MilColorF fourTuple; ConvertValueToMilColorF(newValue, out fourTuple); StashInPosition(ref _floatRegisters, registerIndex, fourTuple, registerMax, ref _floatCount); } else if (t == typeof(int)) { MilColorI fourTuple; ConvertValueToMilColorI(newValue, out fourTuple); StashInPosition(ref _intRegisters, registerIndex, fourTuple, registerMax, ref _intCount); } else if (t == typeof(bool)) { StashInPosition(ref _boolRegisters, registerIndex, (bool)newValue, registerMax, ref _boolCount); } else { // We should have converted all acceptable types. 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(BitmapCacheBrush).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"); } } // // Treat as ps_2_0 by default // int registerMax = PS_2_0_SAMPLER_LIMIT; string srid = SRID.Effect_Shader20SamplerRegisterLimit; if (PixelShader != null && PixelShader.ShaderMajorVersion >= 3) { registerMax = PS_3_0_SAMPLER_LIMIT; srid = SRID.Effect_Shader30SamplerRegisterLimit; } if (registerIndex >= registerMax || registerIndex < 0) { throw new ArgumentException(SR.Get(srid)); } SamplerData sd = new SamplerData() { _brush = (Brush)newValue, _samplingMode = samplingMode }; StashSamplerDataInPosition(registerIndex, sd, registerMax); // 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 uint 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.ShaderConstantIntRegistersSize = (uint)(sizeof(Int16) * _intCount); data.DependencyPropertyIntValuesSize = (uint)(4 * sizeof(Int32) * _intCount); data.ShaderConstantBoolRegistersSize = (uint)(sizeof(Int16) * _boolCount); // // Note: the multiply by 4 is not because the boolean register holds 4 // values, but to compensate for the difference between sizeof(bool) // in managed code (1) and sizeof(BOOL) in native code (4). // data.DependencyPropertyBoolValuesSize = (uint)(4 * sizeof(bool) * _boolCount); 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.ShaderConstantIntRegistersSize + data.DependencyPropertyIntValuesSize + data.ShaderConstantBoolRegistersSize + data.DependencyPropertyBoolValuesSize + data.ShaderSamplerRegistrationInfoSize + data.DependencyPropertySamplerValuesSize ) ); // Arrays appear in this order: // 1) float register indices // 2) float dp values // 3) int register indices // 4) int dp values // 5) bool register indices // 6) bool dp values // 7) sampler registration info // 8) 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) int register indices AppendRegisters(channel, _intRegisters); // 4) int dp values if (_intRegisters != null) { for (int i = 0; i < _intRegisters.Count; i++) { MilColorI? v = _intRegisters[i]; if (v.HasValue) { MilColorI valueToPush = v.Value; channel.AppendCommandData((byte*)&valueToPush, sizeof(MilColorI)); } } } // 5) bool register indices AppendRegisters(channel, _boolRegisters); // 6) bool dp values if (_boolRegisters != null) { for (int i = 0; i < _boolRegisters.Count; i++) { bool? v = _boolRegisters[i]; if (v.HasValue) { // // Note: need 4 bytes for the bool, because the render thread // unmarshals it into a 4-byte BOOL. See the comment above for // DependencyPropertyBoolValuesSize for more details. // Int32 valueToPush = v.Value ? 1 : 0; channel.AppendCommandData((byte*)&valueToPush, sizeof(Int32)); } } } // 7) 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)); } } } // 8) 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(this, 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 in ps_2_0. Ints and bools are // also supported in ps_3_0. internal static Type DetermineShaderConstantType(Type type, PixelShader pixelShader) { 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); } else if (pixelShader != null && pixelShader.ShaderMajorVersion >= 3) { // // int and bool are also supported by ps_3_0. // if (type == typeof(int) || type == typeof(uint) || type == typeof(byte) || type == typeof(sbyte) || type == typeof(long) || type == typeof(ulong) || type == typeof(short) || type == typeof(ushort) || type == typeof(char)) { result = typeof(int); } else if (type == typeof(bool)) { result = typeof(bool); } } 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; } } // Convert to int four tuple internal static void ConvertValueToMilColorI(object value, out MilColorI newVal) { Type t = value.GetType(); // Fill in four-tuples. Always fill in 1's for where there are // empty slots, to avoid division by zero on vector operations that // these values are subjected to. int iVal = 1; // // Note: conversions from long/ulong/uint can change the sign of the number // if (t == typeof(long)) { iVal = (int)(long)value; } else if (t == typeof(ulong)) { iVal = (int)(ulong)value; } else if (t == typeof(uint)) { iVal = (int)(uint)value; } else if (t == typeof(short)) { iVal = (int)(short)value; } else if (t == typeof(ushort)) { iVal = (int)(ushort)value; } else if (t == typeof(byte)) { iVal = (int)(byte)value; } else if (t == typeof(sbyte)) { iVal = (int)(sbyte)value; } else if (t == typeof(char)) { iVal = (int)(char)value; } else { iVal = (int)value; } // Scalars extend out to fill entire vector. newVal.r = newVal.g = newVal.b = newVal.a = iVal; } /// /// 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; } 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 _intRegisters = null; private List _boolRegisters = null; private List _samplerData = null; private uint _floatCount = 0; private uint _intCount = 0; private uint _boolCount = 0; private uint _samplerCount = 0; private int _ddxUvDdyUvRegisterIndex = -1; private const int PS_2_0_FLOAT_REGISTER_LIMIT = 32; private const int PS_3_0_FLOAT_REGISTER_LIMIT = 224; private const int PS_3_0_INT_REGISTER_LIMIT = 16; private const int PS_3_0_BOOL_REGISTER_LIMIT = 16; // ps_2_0 allows max 16, but some cards seem to have trouble with 16 samplers being set. // Restricting to 4 for now. private const int PS_2_0_SAMPLER_LIMIT = 4; private const int PS_3_0_SAMPLER_LIMIT = 8; } } // 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
- HttpDictionary.cs
- WaitHandle.cs
- XsltFunctions.cs
- DesignerActionUIService.cs
- shaperfactoryquerycacheentry.cs
- TextBlock.cs
- safePerfProviderHandle.cs
- Compiler.cs
- KeyGestureConverter.cs
- NavigationPropertyAccessor.cs
- ContextMenu.cs
- PinnedBufferMemoryStream.cs
- CodeCastExpression.cs
- PropertyKey.cs
- JoinGraph.cs
- CharAnimationBase.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- FloaterBaseParagraph.cs
- MetadataItemSerializer.cs
- PrintPreviewDialog.cs
- MetadataItem.cs
- Signature.cs
- SettingsProperty.cs
- SingleObjectCollection.cs
- SectionInput.cs
- SqlTriggerContext.cs
- CorrelationInitializer.cs
- BaseValidator.cs
- OleDbStruct.cs
- NativeMethods.cs
- WebPartEditorCancelVerb.cs
- FormViewPageEventArgs.cs
- NameValueFileSectionHandler.cs
- RowType.cs
- StreamResourceInfo.cs
- SelectorAutomationPeer.cs
- StateManagedCollection.cs
- WSFederationHttpSecurity.cs
- StringReader.cs
- CompositionTarget.cs
- ToolStripItemRenderEventArgs.cs
- DefaultValueConverter.cs
- FormsAuthenticationTicket.cs
- HtmlInputFile.cs
- WorkflowElementDialog.cs
- PackageProperties.cs
- AudienceUriMode.cs
- TextDocumentView.cs
- PathSegmentCollection.cs
- TextServicesCompartment.cs
- DbReferenceCollection.cs
- ValidatorCollection.cs
- Win32Exception.cs
- DesignerActionMethodItem.cs
- ListenerAdaptersInstallComponent.cs
- FieldToken.cs
- TemplateBuilder.cs
- SetStoryboardSpeedRatio.cs
- TemplateControl.cs
- SecondaryIndexList.cs
- XmlElementAttributes.cs
- StyleXamlParser.cs
- CompressionTransform.cs
- AutomationPropertyInfo.cs
- SecurityToken.cs
- XmlCharType.cs
- Literal.cs
- XmlSerializerAssemblyAttribute.cs
- RoutedEventArgs.cs
- _emptywebproxy.cs
- EllipseGeometry.cs
- CodeAccessSecurityEngine.cs
- CategoryValueConverter.cs
- HtmlAnchor.cs
- AssemblyInfo.cs
- DelayLoadType.cs
- DBDataPermission.cs
- CommonXSendMessage.cs
- PropertyGridDesigner.cs
- ParameterCollection.cs
- UrlMapping.cs
- KnownBoxes.cs
- ItemsPanelTemplate.cs
- FormsAuthenticationModule.cs
- StatusBarItem.cs
- SettingsPropertyValue.cs
- Section.cs
- KeyedHashAlgorithm.cs
- XmlBinaryReader.cs
- ObjectDataProvider.cs
- LinqDataView.cs
- DynamicRouteExpression.cs
- Propagator.cs
- WebPartAuthorizationEventArgs.cs
- TextTreeExtractElementUndoUnit.cs
- BindValidator.cs
- FontInfo.cs
- SynchronizedDispatch.cs
- PackagePartCollection.cs
- DataGridViewLinkCell.cs