ShaderEffect.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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 Freezable.CloneCore. 
        /// 
        ///  
        protected override void CloneCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.CloneCore(sourceFreezable);
            CopyCommon(effect);
        }
 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore. 
        /// 
        ///  
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable;
            base.CloneCurrentValueCore(sourceFreezable); 
            CopyCommon(effect);
        } 
 

        ///  
        /// Implementation of Freezable.GetAsFrozenCore.
        /// 
        /// 
        protected override void GetAsFrozenCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.GetAsFrozenCore(sourceFreezable); 
            CopyCommon(effect);
        } 


        /// 
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore. 
        /// 
        ///  
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.GetCurrentValueAsFrozenCore(sourceFreezable);
            CopyCommon(effect);
        }
 
        /// 
        /// 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 Freezable.CloneCore. 
        /// 
        ///  
        protected override void CloneCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.CloneCore(sourceFreezable);
            CopyCommon(effect);
        }
 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore. 
        /// 
        ///  
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable;
            base.CloneCurrentValueCore(sourceFreezable); 
            CopyCommon(effect);
        } 
 

        ///  
        /// Implementation of Freezable.GetAsFrozenCore.
        /// 
        /// 
        protected override void GetAsFrozenCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.GetAsFrozenCore(sourceFreezable); 
            CopyCommon(effect);
        } 


        /// 
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore. 
        /// 
        ///  
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) 
        {
            ShaderEffect effect = (ShaderEffect)sourceFreezable; 
            base.GetCurrentValueAsFrozenCore(sourceFreezable);
            CopyCommon(effect);
        }
 
        /// 
        /// 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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK