4 using System.Collections.Generic;
7 using SiliconStudio.Shaders.Ast;
8 using SiliconStudio.Shaders.Ast.Hlsl;
9 using SiliconStudio.Shaders.Visitor;
11 namespace SiliconStudio.Shaders.Convertor
18 private Dictionary<SamplerTextureKey, Variable> samplerMapping;
19 private HashSet<Variable> textureAccesses;
21 private List<TextureSamplerMethodKey> textureSamplerMethods =
new List<TextureSamplerMethodKey>();
22 private static readonly
object ScopeValueKey =
new object();
28 this.samplerMapping = samplerMapping;
29 textureAccesses =
new HashSet<Variable>();
32 foreach (var variable
in shader.Declarations)
34 cloneContext.Add(variable, variable);
45 public bool TextureFunctionsCompatibilityProfile {
get; set; }
49 base.Run(methodEntry);
51 var existingTextures =
new HashSet<Variable>(samplerMapping.Select(x => x.Key.Texture));
52 foreach (var texture
in textureAccesses)
54 if (!existingTextures.Contains(texture))
55 GenerateGLSampler(null, texture);
58 for (
int i = this.textureSamplerMethods.Count - 1; i >= 0; i--)
60 var textureSamplerMethodKey = this.textureSamplerMethods[i];
61 var entryIndex = shader.Declarations.IndexOf(textureSamplerMethodKey.Method);
62 this.shader.Declarations.Insert(entryIndex, textureSamplerMethodKey.NewMethod);
69 if (variableRef != null)
71 var variable = variableRef.TypeInference.Declaration as
Variable;
76 if (!shader.Declarations.Contains(variable) && variable.InitialValue != null)
78 return this.FindGlobalVariable(variable.InitialValue);
81 variable = (Variable)variable.
GetTag(ScopeValueKey) ?? variable;
84 if (shader.Declarations.Contains(variable))
94 protected void Visit(VariableReferenceExpression variableRef)
96 ((ScopeDeclarationWithRef)ScopeStack.Peek()).VariableReferences.Add(variableRef);
102 base.Visit(methodInvocationExpression);
105 var variableRef = methodInvocationExpression.Target as VariableReferenceExpression;
107 if (memberRef != null)
110 var textureVariable = this.FindGlobalVariable(memberRef.Target);
112 if (textureVariable != null)
114 var textureType = textureVariable.Type.ResolveType();
116 if (textureType is
TextureType || (textureType.IsBuiltIn && textureType.Name.Text.StartsWith(
"Texture", StringComparison.InvariantCultureIgnoreCase)))
118 switch (memberRef.Member)
122 GenerateGLSampler(null, textureVariable);
125 case "GetDimensions":
127 textureAccesses.Add(textureVariable);
135 var sampler = this.FindGlobalVariable(methodInvocationExpression.Arguments[0]);
137 throw new InvalidOperationException(
string.Format(
"Unable to find sampler [{0}] as a global variable",
138 methodInvocationExpression.
Arguments[0]));
140 GenerateGLSampler(sampler, textureVariable);
147 else if (variableRef != null)
149 string methodName = variableRef.Name.Text;
152 var texFetchInfo = ParseTexFetch(methodName);
153 if (texFetchInfo != null)
155 var fetchInstructionSecondPart = string.Empty;
156 switch (texFetchInfo.Item2)
158 case TexFetchType.Default:
159 if (methodInvocationExpression.
Arguments.Count == 4)
160 fetchInstructionSecondPart =
"Grad";
162 case TexFetchType.Bias:
166 case TexFetchType.Grad:
167 fetchInstructionSecondPart =
"Grad";
169 case TexFetchType.Proj:
170 fetchInstructionSecondPart =
"Proj";
172 case TexFetchType.Lod:
173 fetchInstructionSecondPart =
"Lod";
180 if (TextureFunctionsCompatibilityProfile)
182 var stringBuilder =
new StringBuilder(
"texture", 32);
183 if (texFetchInfo.Item1 == 4)
184 stringBuilder.Append(
"Cube");
186 stringBuilder.Append(texFetchInfo.Item1).Append(
'D');
187 stringBuilder.Append(fetchInstructionSecondPart);
188 variableRef.Name = stringBuilder.ToString();
192 variableRef.Name =
"texture" + fetchInstructionSecondPart;
196 if (texFetchInfo.Item2 != TexFetchType.Proj)
198 var previousArgument = methodInvocationExpression.Arguments[1];
199 var sizeOfArguments = texFetchInfo.Item1 == 4 ? 3 : texFetchInfo.Item1;
200 var vectorType = previousArgument.TypeInference.TargetType as
VectorType;
203 if (vectorType == null || vectorType.Dimension != sizeOfArguments)
204 methodInvocationExpression.Arguments[1] =
new MemberReferenceExpression(
new ParenthesizedExpression(previousArgument),
"xyzw".Substring(0, sizeOfArguments));
208 var samplerRefExpr = methodInvocationExpression.Arguments[0] as VariableReferenceExpression;
209 if (samplerRefExpr != null)
211 var samplerVariable = samplerRefExpr.TypeInference.Declaration as Variable;
212 var newSamplerType = texFetchInfo.Item1 < 4 ?
new SamplerType(
"sampler" + texFetchInfo.Item1 +
"D") :
new SamplerType(
"samplerCube");
213 this.ChangeVariableType(samplerVariable, newSamplerType);
219 private void ChangeVariableType(Variable samplerVariable,
TypeBase newType)
221 if (samplerVariable != null)
223 samplerVariable.Type = newType;
229 var variableInitialValue = samplerVariable.InitialValue as VariableReferenceExpression;
230 if (variableInitialValue != null)
232 this.ChangeVariableType(variableInitialValue.TypeInference.Declaration as Variable, newType);
239 var textureParameters =
new List<Parameter>();
240 var parameterValues =
new List<Expression>();
241 var parameterGlobalValues =
new List<Variable>();
243 var samplerTypes =
new List<int>();
245 for (
int i = 0; i < method.Parameters.Count; i++)
247 var parameter = method.Parameters[i];
250 textureParameters.Add(parameter);
253 var parameterValue = this.FindGlobalVariable(invoke.Arguments[i]);
256 parameter.SetTag(ScopeValueKey, parameterValue);
259 if (!parameterGlobalValues.Contains(parameterValue))
260 parameterGlobalValues.Add(parameterValue);
264 parameterValues.Add(invoke.Arguments[i]);
273 if (textureParameters.Count > 0)
276 parameterGlobalValues.Sort((left, right) => left.Name.Text.CompareTo(right.Name.Text));
278 var methodKey =
new TextureSamplerMethodKey(method);
280 int indexOf = textureSamplerMethods.IndexOf(methodKey);
284 methodKey.Initialize(cloneContext);
285 textureSamplerMethods.Add(methodKey);
290 methodKey = textureSamplerMethods[indexOf];
291 textureSamplerMethods.RemoveAt(indexOf);
292 textureSamplerMethods.Add(methodKey);
295 methodKey.Invokers.Add(invoke);
297 var newTarget =
new VariableReferenceExpression(methodKey.NewMethod.Name) {
TypeInference = { Declaration = methodKey.NewMethod, TargetType = invoke.TypeInference.TargetType } };
298 invoke.Target = newTarget;
299 invoke.Arguments = parameterValues;
300 invoke.TypeInference.Declaration = methodKey.NewMethod;
301 invoke.TypeInference.TargetType = invoke.TypeInference.TargetType;
303 this.VisitDynamic(methodKey.NewMethod);
308 this.VisitDynamic(method);
312 if (samplerTypes.Count > 0)
314 foreach (var samplerTypeIndex
in samplerTypes)
316 var samplerRef = invoke.Arguments[samplerTypeIndex] as VariableReferenceExpression;
317 if (samplerRef != null)
319 var samplerDecl = samplerRef.TypeInference.Declaration as Variable;
320 ChangeVariableType(samplerDecl, method.
Parameters[samplerTypeIndex].Type);
327 if (textureParameters.Count > 0)
329 foreach (var textureParameter
in textureParameters)
331 textureParameter.RemoveTag(ScopeValueKey);
341 private void GenerateGLSampler(Variable sampler, Variable texture)
343 Variable glslSampler;
346 throw new InvalidOperationException();
349 if (!samplerMapping.TryGetValue(samplerKey, out glslSampler))
351 glslSampler =
new Variable(
new TypeName(texture.
Type.
ResolveType().Name.Text.Replace(
"Texture",
"sampler")), texture.Name + (sampler != null ?
"_" + sampler.Name :
"_NoSampler")) { Span = sampler == null ? texture.Span : sampler.Span };
352 samplerMapping.Add(samplerKey, glslSampler);
365 private static Tuple<int, TexFetchType> ParseTexFetch(
string name)
367 if (!name.StartsWith(
"tex"))
370 name = name.Substring(3);
374 if (name.StartsWith(
"1D"))
376 else if (name.StartsWith(
"2D"))
378 else if (name.StartsWith(
"3D"))
380 else if (name.StartsWith(
"CUBE"))
386 name = name.Substring((dimension == 4) ? 4 : 2);
388 TexFetchType fetchType;
392 fetchType = TexFetchType.Default;
395 fetchType = TexFetchType.Lod;
398 fetchType = TexFetchType.Grad;
401 fetchType = TexFetchType.Bias;
404 fetchType = TexFetchType.Proj;
410 return new Tuple<int, TexFetchType>(dimension, fetchType);
417 private enum TexFetchType
447 return new ScopeDeclarationWithRef(container);
452 public ScopeDeclarationWithRef()
458 : base(scopeContainer)
460 VariableReferences =
new List<VariableReferenceExpression>();
463 public List<VariableReferenceExpression> VariableReferences {
get;
private set; }
468 private class TextureSamplerMethodKey
470 private string methodName;
474 Invokers =
new List<MethodInvocationExpression>();
475 this.Method = method;
477 Variables =
new List<Variable>();
478 foreach (var parameter
in Method.Parameters)
480 var variableValue = (Variable)parameter.
GetTag(ScopeValueKey);
481 if (variableValue != null)
483 Variables.Add(variableValue);
488 public List<MethodInvocationExpression> Invokers {
get; set; }
490 public void Initialize(
CloneContext previousCloneContext)
495 foreach (var keyValurPair
in previousCloneContext)
497 cloneContext.Add(keyValurPair.Key, keyValurPair.Value);
501 cloneContext.Remove(
Method);
504 NewMethod = Method.DeepClone(cloneContext);
506 var oldParameters = NewMethod.Parameters;
507 NewMethod.Parameters =
new List<Parameter>();
509 for (
int i = 0; i < oldParameters.Count; i++)
511 var parameter = oldParameters[i];
512 var variableValue = (Variable)this.
Method.Parameters[i].GetTag(ScopeValueKey);
513 if (variableValue != null)
517 parameter.InitialValue =
new VariableReferenceExpression(variableValue.Name) {
TypeInference = { Declaration = variableValue, TargetType = variableValue.Type } };
520 NewMethod.Parameters.Add(parameter);
524 var methodNameBuild =
new StringBuilder();
525 methodNameBuild.Append(Method.Name);
526 foreach (var variable
in Variables)
528 methodNameBuild.Append(
"_");
529 methodNameBuild.Append(variable.Name);
531 methodName = methodNameBuild.ToString();
532 NewMethod.Name = methodName;
537 public List<Variable> Variables {
get;
private set; }
541 public bool Equals(TextureSamplerMethodKey other)
543 if (ReferenceEquals(null, other))
545 if (ReferenceEquals(
this, other))
548 if (this.Variables.Count != other.Variables.Count)
551 if (!ReferenceEquals(other.Method,
this.Method))
554 for (
int i = 0; i < this.Variables.Count; i++)
556 if (!ReferenceEquals(this.Variables[i], other.Variables[i]))
563 public override bool Equals(
object obj)
565 if (ReferenceEquals(null, obj))
567 if (ReferenceEquals(
this, obj))
569 if (obj.GetType() != typeof(TextureSamplerMethodKey))
571 return Equals((TextureSamplerMethodKey)obj);
574 public override int GetHashCode()
579 foreach (var variable
in Variables)
581 result = (result * 397) ^ variable.GetHashCode();
583 result = (result * 397) ^ (this.Method != null ? this.
Method.GetHashCode() : 0);
588 public override string ToString()
590 return NewMethod == null ?
"[" + Method.Name.Text +
"]" : NewMethod.Name.Text;
Base class for all vector types
TypeBase Type
Gets or sets the type.
Tag a visitable method with this attribute.
A tag interface to identify a container for scope declarations.
A Scope declaration provides a way to retrieve all scope declaration (variable, methods...etc.) and attached nodes.
virtual TypeBase ResolveType()
Resolves the type.
override void ProcessMethodInvocation(MethodInvocationExpression invoke, MethodDefinition method)
override ScopeDeclaration NewScope(IScopeContainer container=null)
An expression surrounded by parenthesis.
A method definition with a body of statements.
Use the default mode depending on the type of the field/property.
A declaration inside a statement.
A single parameter declaration.
List< Expression > Arguments
Gets or sets the arguments.
A member reference in the form {this}.{Name}
Provides a dictionary of cloned values, where the [key] is the original object and [value] the new ob...
Toplevel container of a shader parsing result.
List< Parameter > Parameters
Gets or sets the parameters.
A reference to a variable.
SamplerMappingVisitor(Shader shader, Dictionary< SamplerTextureKey, Variable > samplerMapping)
override void Visit(MethodInvocationExpression methodInvocationExpression)
override void Run(MethodDefinition methodEntry)
Collect the texture and sampler pair used in the HLSL shader.
object GetTag(object tagKey)
Gets a tag value associated to this node..
void Visit(VariableReferenceExpression variableRef)