public void TestMacrosArray() { // test that macros are correctly used through an array var baseMixin = new ShaderMixinSource(); baseMixin.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D", 1); baseMixin.Macros.Add(new ShaderMacro("MACRO_TEST", "int")); baseMixin.Mixins.Add(new ShaderClassSource("TestMacrosArray")); var compositionArray = new ShaderArraySource(); var macros0 = new ShaderMixinSource(); macros0.Mixins.Add(new ShaderClassSource("MacroTest")); compositionArray.Add(macros0); var macros1 = new ShaderMixinSource(); macros1.Mixins.Add(new ShaderClassSource("MacroTest")); macros1.Macros.Add(new ShaderMacro("MACRO_TEST", "float")); compositionArray.Add(macros1); var macros2 = new ShaderMixinSource(); macros2.Mixins.Add(new ShaderClassSource("MacroTest")); macros2.Macros.Add(new ShaderMacro("MACRO_TEST", "float4")); compositionArray.Add(macros2); baseMixin.Compositions.Add("macrosArray", compositionArray); var parsingResult = shaderMixinParser.Parse(baseMixin, baseMixin.Macros.ToArray()); Assert.IsFalse(parsingResult.HasErrors); var cBufferVar = parsingResult.Shader.Declarations.OfType <ConstantBuffer>().First(x => x.Name == "Globals").Members.OfType <Variable>().ToList(); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "int")); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "float")); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "float4")); }
public void TestMacrosArray() { // test that macros are correctly used through an array var baseMixin = new ShaderMixinSource(); baseMixin.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D", 1); baseMixin.Macros.Add(new ShaderMacro("MACRO_TEST", "int")); baseMixin.Mixins.Add(new ShaderClassSource("TestMacrosArray")); var compositionArray = new ShaderArraySource(); var macros0 = new ShaderMixinSource(); macros0.Mixins.Add(new ShaderClassSource("MacroTest")); compositionArray.Add(macros0); var macros1 = new ShaderMixinSource(); macros1.Mixins.Add(new ShaderClassSource("MacroTest")); macros1.Macros.Add(new ShaderMacro("MACRO_TEST", "float")); compositionArray.Add(macros1); var macros2 = new ShaderMixinSource(); macros2.Mixins.Add(new ShaderClassSource("MacroTest")); macros2.Macros.Add(new ShaderMacro("MACRO_TEST", "float4")); compositionArray.Add(macros2); baseMixin.Compositions.Add("macrosArray", compositionArray); var parsingResult = shaderMixinParser.Parse(baseMixin, baseMixin.Macros.ToArray()); Assert.IsFalse(parsingResult.HasErrors); var cBufferVar = parsingResult.Shader.Declarations.OfType<ConstantBuffer>().First(x => x.Name == "Globals").Members.OfType<Variable>().ToList(); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "int")); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "float")); Assert.AreEqual(1, cBufferVar.Count(x => x.Type.Name.Text == "float4")); }
public void SetupShadersPermutationReceiver(EffectShaderPass effectPass, object permutationKey) { var currentShadowMapsPermutation = (ShadowMapPermutationArray)permutationKey; if (currentShadowMapsPermutation.ShadowMaps.Count == 0) { return; } var shadowsArray = new ShaderArraySource(); effectPass.Shader.Mixins.Add("ShadowMapReceiver"); effectPass.Shader.Compositions.Add("shadows", shadowsArray); // Group by shadow map types (one group can be processed in the same loop). // Currently based on filtering type and number of cascades (but some more parameters might affect this later as new type of shadow maps are introduced). var shadowMapTypes = currentShadowMapsPermutation.ShadowMaps.GroupBy(x => Tuple.Create(x.ShadowMap.Filter.GetType(), x.ShadowMap.LevelCount, x.ShadowMap.Texture)); int shadowMapTypeIndex = 0; foreach (var shadowMapType in shadowMapTypes) { var shadowMapTypeCopy = shadowMapType.ToArray(); var shadowMixin = new ShaderMixinSource(); // Currently use shadow map count, but we should probably use next power of two to limit number of permutations. var maxShadowMapCount = shadowMapTypeCopy.Length; // Setup shadow mapping shadowMixin.Mixins.Add(new ShaderClassSource("ShadowMapCascadeBase", shadowMapType.Key.Item2, 0, maxShadowMapCount, 1)); //shadowMixin.Mixins.Add(new ShaderClassSource("LightDirectionalShading", shadowMapPermutation.Index)); // Setup the filter // TODO: Use static based on type of filter? (should use Key instead of First()). shadowMixin.Mixins.Add(shadowMapType.First().ShadowMap.Filter.GenerateShaderSource(maxShadowMapCount)); shadowsArray.Add(shadowMixin); // Register keys for this shadow map type var shadowSubKey = string.Format(".shadows[{0}]", shadowMapTypeIndex++); effectPass.Parameters.Set(ShadowMapKeys.Texture.AppendKey(shadowSubKey), shadowMapType.Key.Item3); effectPass.Parameters.Set(LightingPlugin.ShadowMapLightCount.AppendKey(shadowSubKey), shadowMapTypeCopy.Length); effectPass.Parameters.AddDynamic(LightingPlugin.ReceiverInfo.AppendKey(shadowSubKey), ParameterDynamicValue.New(ShadowMapPermutationArray.Key, TransformationKeys.World, TransformationKeys.ViewProjection, (ref ShadowMapPermutationArray shadowMapPermutations, ref Matrix world, ref Matrix viewProj, ref ShadowMapReceiverInfo[] output) => { unsafe { for (int i = 0; i < shadowMapTypeCopy.Length; ++i) { var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters; // TODO: Optimize dictionary access this using SetKeyMapping var shadowMapData = permutationParameters.Get(LightingPlugin.ViewProjectionArray); var textureCoords = permutationParameters.Get(LightingPlugin.CascadeTextureCoordsBorder); var distanceMax = permutationParameters.Get(ShadowMapKeys.DistanceMax); var lightDirection = permutationParameters.Get(LightKeys.LightDirection); Matrix *vpPtr = &shadowMapData.ViewProjReceiver0; fixed(Matrix * wvpPtr = &output[i].WorldViewProjReceiver0) { for (int j = 0; j < 4; ++j) { Matrix.Multiply(ref world, ref vpPtr[j], ref wvpPtr[j]); } } output[i].Offset0 = shadowMapData.Offset0; output[i].Offset1 = shadowMapData.Offset1; output[i].Offset2 = shadowMapData.Offset2; output[i].Offset3 = shadowMapData.Offset3; fixed(Vector4 * targetPtr = &output[i].CascadeTextureCoordsBorder0) fixed(Vector4 * sourcePtr = &textureCoords[0]) { for (int j = 0; j < 4; ++j) { targetPtr[j] = sourcePtr[j]; } } output[i].ShadowLightDirection = lightDirection; LightKeys.LightDirectionVSUpdate(ref output[i].ShadowLightDirection, ref viewProj, ref output[i].ShadowLightDirectionVS); output[i].ShadowMapDistance = distanceMax; output[i].ShadowLightColor = shadowMapData.LightColor; } } }, autoCheckDependencies: false)); // Always update (permutation won't get updated, only its content)! // Register VSM filter if necessary if (shadowMapType.Key.Item1 == typeof(ShadowMapFilterVsm)) { effectPass.Parameters.AddDynamic(LightingPlugin.ReceiverVsmInfo.AppendKey(shadowSubKey), ParameterDynamicValue.New(ShadowMapPermutationArray.Key, (ref ShadowMapPermutationArray shadowMapPermutations, ref ShadowMapReceiverVsmInfo[] output) => { for (int i = 0; i < shadowMapTypeCopy.Length; ++i) { var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters; output[i].BleedingFactor = permutationParameters.Get(ShadowMapFilterVsm.VsmBleedingFactor); output[i].MinVariance = permutationParameters.Get(ShadowMapFilterVsm.VsmMinVariance); } }, autoCheckDependencies: false)); } } }