Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
EffectCompileCommand.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using SiliconStudio.Assets.Compiler;
10 using SiliconStudio.BuildEngine;
11 using SiliconStudio.Core;
12 using SiliconStudio.Core.Diagnostics;
13 using SiliconStudio.Core.IO;
14 using SiliconStudio.Core.Serialization;
15 using SiliconStudio.Core.Serialization.Assets;
16 using SiliconStudio.Core.Storage;
17 using SiliconStudio.Paradox.Effects;
18 using SiliconStudio.Paradox.Shaders;
19 using SiliconStudio.Paradox.Shaders.Compiler;
20 
21 namespace SiliconStudio.Paradox.Assets.Effect
22 {
23  /// <summary>
24  /// This command is responsible to compile a single permutation of an effect (pdxfx or pdxsl)
25  /// </summary>
26  internal class EffectCompileCommand : IndexFileCommand
27  {
28  #region Static method
29  public static readonly PropertyKey<EffectCompilerBase> CompilerKey = new PropertyKey<EffectCompilerBase>("CompilerKey", typeof(EffectCompileCommand));
30 
31  public static EffectCompilerBase GetOrCreateEffectCompiler(AssetCompilerContext context)
32  {
33  lock (context)
34  {
35  var compiler = context.Properties.Get(CompilerKey);
36  if (compiler == null)
37  {
38  // Create compiler
39  var effectCompiler = new Shaders.Compiler.EffectCompiler();
40  effectCompiler.SourceDirectories.Add(EffectSystem.DefaultSourceShaderFolder);
41  compiler = new EffectCompilerCache(effectCompiler);
42  context.Properties.Set(CompilerKey, compiler);
43 
44  var shaderLocations = context.Properties.Get(EffectShaderAssetCompiler.ShaderLocationsKey);
45 
46  // Temp copy URL to absolute file path to inform the compiler the absolute file location
47  // of all pdxsl files.
48  if (shaderLocations != null)
49  {
50  foreach (var shaderLocation in shaderLocations)
51  {
52  effectCompiler.UrlToFilePath[shaderLocation.Key] = shaderLocation.Value;
53  }
54  }
55  }
56 
57  return compiler;
58  }
59  }
60 
61  #endregion
62 
63  private readonly AssetCompilerContext context;
64  private UDirectory baseUrl;
65  private string effectName;
66  private CompilerParameters compilerParameters;
67  private static Dictionary<string, int> PermutationCount = new Dictionary<string, int>();
68 
69  public EffectCompileCommand(AssetCompilerContext context, UDirectory baseUrl, string effectName, CompilerParameters compilerParameters)
70  {
71  this.context = context;
72  this.effectName = effectName;
73  this.baseUrl = baseUrl;
74  this.compilerParameters = compilerParameters;
75  }
76 
77  public override string Title
78  {
79  get
80  {
81  return string.Format("EffectCompile [{0}]", effectName);
82  }
83  }
84 
85  protected override void ComputeParameterHash(BinarySerializationWriter writer)
86  {
87  base.ComputeParameterHash(writer);
88  writer.Serialize(ref effectName, ArchiveMode.Serialize);
89  writer.Serialize(ref compilerParameters, ArchiveMode.Serialize);
90  }
91 
92  protected override void ComputeAssemblyHash(BinarySerializationWriter writer)
93  {
94  writer.Write(DataSerializer.BinaryFormatVersion);
95 
96  // Since EffectBytecode format is quite stable, we want to manually control it's assembly hash here
97  writer.Write(1);
98  }
99 
100  protected override Task<ResultStatus> DoCommandOverride(ICommandContext commandContext)
101  {
102  var compiler = GetOrCreateEffectCompiler(context);
103 
104  var isPdxfx = ShaderMixinManager.Contains(effectName);
105  var source = isPdxfx ? new ShaderMixinGeneratorSource(effectName) : (ShaderSource)new ShaderClassSource(effectName);
106 
107  int permutationCount;
108  lock (PermutationCount)
109  {
110  PermutationCount.TryGetValue(effectName, out permutationCount);
111  permutationCount++;
112  PermutationCount[effectName] = permutationCount;
113  }
114  commandContext.Logger.Info("Create permutation #{0} for effect [{1}]: \n{2}", permutationCount, effectName, compilerParameters.ToStringDetailed());
115 
116  var compilerResults = compiler.Compile(source, compilerParameters, null, null);
117 
118  // Copy logs and if there are errors, exit directlry
119  compilerResults.CopyTo(commandContext.Logger);
120  if (compilerResults.HasErrors)
121  {
122  return Task.FromResult(ResultStatus.Failed);
123  }
124 
125  // Register all dependencies
126  var bytecode = compilerResults.MainBytecode;
127  foreach (var hashSource in bytecode.HashSources)
128  {
129  commandContext.Logger.Verbose("Shader [{0}] is using [{1}]", effectName, hashSource.Key);
130  commandContext.RegisterInputDependency(new ObjectUrl(UrlType.Internal, hashSource.Key));
131  }
132 
133  // Generate sourcecode if configured
134  if (compilerParameters.ContainsKey(EffectSourceCodeKeys.Enable))
135  {
136  var outputDirectory = UPath.Combine(context.Package.RootDirectory, baseUrl);
137  var outputClassFile = effectName + ".bytecode." + compilerParameters.Platform + "." + compilerParameters.Profile + ".cs";
138  var fullOutputClassFile = Path.Combine(outputDirectory, outputClassFile);
139 
140  commandContext.Logger.Info("Writing shader bytecode to .cs source [{0}]", fullOutputClassFile);
141  using (var stream = new FileStream(fullOutputClassFile, FileMode.Create, FileAccess.Write, FileShare.Write))
142  EffectByteCodeToSourceCodeWriter.Write(effectName, compilerParameters, bytecode, new StreamWriter(stream, Encoding.UTF8));
143  }
144 
145  return Task.FromResult(ResultStatus.Successful);
146  }
147 
148  public override string ToString()
149  {
150  return Title;
151  }
152  }
153 }
A shader source that is linked to a pdxfx effect.
Checks if an effect has already been compiled in its cache before deferring to a real IEffectCompiler...
Base class for implementations of IEffectCompiler, providing some helper functions.
System.Text.Encoding Encoding
System.IO.FileMode FileMode
Definition: ScriptSync.cs:33
Implements SerializationStream as a binary writer.
The context used when compiling an asset in a Package.
Defines a normalized directory path. See UPath for details. This class cannot be inherited.
Definition: UDirectory.cs:13
A Command that reads and/or writes to the index file.
A class that represents a tag propety.
Definition: PropertyKey.cs:17
static readonly ParameterKey< bool > Enable
When compiling a pdxsl, this will generate a source code file