using System; using System.Runtime.InteropServices; using Dx11 = SharpDX.Direct3D11; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. // For details see: http://anxframework.codeplex.com/license namespace ANX.RenderSystem.Windows.Metro.Shader { public class ParameterBuffer : IDisposable { #region Private private Dx11.Buffer nativeBuffer; private NativeDxDevice graphicsDevice; private Effect_Metro parentEffect; private int[] parameterOffsets; private byte[] setData; private int dataSize; #endregion #region Constructor public ParameterBuffer(Effect_Metro setParentEffect, NativeDxDevice setGraphicsDevice) { graphicsDevice = setGraphicsDevice; parentEffect = setParentEffect; dataSize = 0; var offsets = new System.Collections.Generic.List(); foreach(var parameter in parentEffect.shader.Parameters) { if (parameter.IsTexture == false) { offsets.Add(dataSize); dataSize += parameter.SizeInBytes; } } parameterOffsets = offsets.ToArray(); setData = new byte[dataSize]; nativeBuffer = new Dx11.Buffer(graphicsDevice.NativeDevice, dataSize, Dx11.ResourceUsage.Default, Dx11.BindFlags.ConstantBuffer, Dx11.CpuAccessFlags.None, Dx11.ResourceOptionFlags.None, 0); } #endregion #region SetParameter (T) public void SetParameter(string parameterName, ref T value) where T : struct { int indexOfParameter = FindParameterIndex(parameterName); if (indexOfParameter == -1) return; int size = Marshal.SizeOf(typeof(T)); byte[] dataToAdd = new byte[size]; IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(value, ptr, true); Marshal.Copy(ptr, setData, parameterOffsets[indexOfParameter], size); Marshal.FreeHGlobal(ptr); } #endregion #region SetParameter (T[]) public void SetParameter(string parameterName, T[] value) where T : struct { int indexOfParameter = FindParameterIndex(parameterName); if (indexOfParameter == -1) return; int sizePerItem = Marshal.SizeOf(typeof(T)); int offset = 0; IntPtr ptr = Marshal.AllocHGlobal(sizePerItem); for (int index = 0; index < value.Length; index++) { Marshal.StructureToPtr(value[index], ptr, true); Marshal.Copy(ptr, setData, parameterOffsets[indexOfParameter] + offset, sizePerItem); offset += sizePerItem; } Marshal.FreeHGlobal(ptr); } #endregion #region SetParameter (float[]) public void SetParameter(string parameterName, float[] value) { int indexOfParameter = FindParameterIndex(parameterName); if (indexOfParameter == -1) return; byte[] result = UnionArraySerializer.Unify(value); Array.Copy(result, 0, setData, parameterOffsets[indexOfParameter], result.Length); } #endregion #region SetParameter (int[]) public void SetParameter(string parameterName, int[] value) { int indexOfParameter = FindParameterIndex(parameterName); if (indexOfParameter == -1) return; byte[] result = UnionArraySerializer.Unify(value); Array.Copy(result, 0, setData, parameterOffsets[indexOfParameter], result.Length); } #endregion #region SetParameter (byte[]) public void SetParameter(string parameterName, byte[] value) { int indexOfParameter = FindParameterIndex(parameterName); if (indexOfParameter == -1) return; Array.Copy(value, 0, setData, parameterOffsets[indexOfParameter], value.Length); } #endregion #region FindParameterIndex private int FindParameterIndex(string parameterName) { int searchIndex = 0; foreach (var parameter in parentEffect.shader.Parameters) { if (parameter.Name == parameterName) return searchIndex; searchIndex++; } return -1; } #endregion #region Apply public void Apply() { graphicsDevice.NativeContext.VertexShader.SetConstantBuffer(0, nativeBuffer); IntPtr dataPtr; unsafe { fixed (byte* ptr = &setData[0]) dataPtr = (IntPtr)ptr; } // Reset really needed? evaluate setData = new byte[dataSize]; var dataBox = new SharpDX.DataBox(dataPtr); graphicsDevice.NativeContext.UpdateSubresource(dataBox, nativeBuffer); } #endregion #region Dispose public void Dispose() { if (nativeBuffer != null) { nativeBuffer.Dispose(); nativeBuffer = null; } graphicsDevice = null; } #endregion } }