Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
HlslToGlslConvertor.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.Globalization;
6 using System.Linq;
7 using System.Text;
8 using SiliconStudio.Shaders.Analysis;
9 using SiliconStudio.Shaders.Analysis.Hlsl;
10 using SiliconStudio.Shaders.Ast;
11 using SiliconStudio.Shaders.Ast.Glsl;
12 using SiliconStudio.Shaders.Ast.Hlsl;
13 using SiliconStudio.Shaders.Parser;
14 using SiliconStudio.Shaders.Utility;
15 using SiliconStudio.Shaders.Visitor;
16 using SiliconStudio.Shaders.Writer.Hlsl;
20 
21 namespace SiliconStudio.Shaders.Convertor
22 {
23 
24 
25  /// <summary>
26  /// HLSL to GLSL conversion requires several steps:
27  /// - Replace input/output structure access by varying variables.
28  /// - Replace common types such as float4 =&gt; vec4.
29  /// - Change main signature.
30  /// - Convert return statements into GLSL out assignments.
31  /// </summary>
33  {
34  // Each sampler+texture pair will map to a GLSL sampler.
35  // KeyValuePair<Variable-SamplerType, Variable-TextureType> => Variable
36  #region Constants and Fields
37 
38  private const string TagLayoutKey = "LAYOUT";
39  private const string VertexIOInterfaceName = "_VertexIO_";
40 
41  private const string gl_FrontFacing = "gl_FrontFacing";
42 
43  private static readonly List<string> SemanticModifiers = new List<string> { "_centroid", "_pp", "_sat" };
44 
45  private readonly bool[] allocatedRegistersForSamplers = new bool[16];
46 
47  private readonly bool[] allocatedRegistersForUniforms = new bool[256];
48 
49  private readonly Dictionary<string, string> builtinGeometryInputs;
50 
51  private readonly Dictionary<string, string> builtinGeometryOutputs;
52 
53  private readonly Dictionary<string, string> builtinPixelInputs;
54 
55  private readonly Dictionary<string, string> builtinPixelOutputs;
56 
57  private readonly Dictionary<string, string> builtinVertexInputs;
58 
59  private readonly Dictionary<string, string> builtinVertexOutputs;
60 
61  private readonly Dictionary<string, TypeBase> builtinGlslTypes;
62 
63  private readonly List<Variable> declarationListToRemove = new List<Variable>();
64 
65  private readonly string entryPointName;
66 
67  private readonly Dictionary<string, string> functionMapping;
68 
69  private readonly Dictionary<Variable, Variable> inputAssignment = new Dictionary<Variable, Variable>(new ReferenceEqualityComparer<Variable>());
70 
71  private readonly List<Variable> listOfMultidimensionArrayVariable = new List<Variable>();
72 
73  private readonly Dictionary<MethodInvocationExpression, bool> methodInvocationHandled = new Dictionary<MethodInvocationExpression, bool>(new ReferenceEqualityComparer<MethodInvocationExpression>());
74 
75  private readonly PipelineStage pipelineStage;
76 
77  private readonly ShaderModel shaderModel;
78 
79  private readonly Dictionary<SamplerTextureKey, Variable> samplerMapping = new Dictionary<SamplerTextureKey, Variable>();
80 
81  private MethodDefinition entryPoint;
82 
83  private string geometryLayoutInput;
84 
85  private Parameter geometryInputParameter;
86 
87  private string geometryLayoutOutput;
88 
89  private List<Variable> inputs = new List<Variable>();
90 
91  private bool isAssignmentTarget;
92 
93  private List<Variable> outputs = new List<Variable>();
94 
95  private ParsingResult parserResult;
96 
97  private Shader shader;
98 
99  private GlobalUniformVisitor globalUniformVisitor;
100 
101  private bool isPixelShaderOutputFragDataMuliType = false;
102 
103  private int breakIndex = 0;
104 
105  #endregion
106 
107  #region Constructors and Destructors
108 
109  /// <summary>
110  /// Initializes a new instance of the <see cref="HlslToGlslConvertor" /> class.
111  /// </summary>
112  /// <param name="entryPointName">Name of the entry point.</param>
113  /// <param name="pipelineStage">The pipeline stage.</param>
114  /// <param name="shaderModel">The shader model.</param>
115  /// <param name="useBuiltinSemantic">if set to <c>true</c> [use builtin semantic].</param>
116  public HlslToGlslConvertor(string entryPointName, PipelineStage pipelineStage, ShaderModel shaderModel, bool useBuiltinSemantic = true)
117  : base(true, true)
118  {
119  this.entryPointName = entryPointName;
120  this.pipelineStage = pipelineStage;
121  this.shaderModel = shaderModel;
122  this.VariableLayouts = new Dictionary<string, VariableLayoutRule>();
123  this.ConstantBufferLayouts = new Dictionary<string, ConstantBufferLayoutRule>();
124  this.MapRules = new Dictionary<string, MapRule>();
125  this.KeepConstantBuffer = true;
126 
127  if (useBuiltinSemantic)
128  {
129  builtinVertexInputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase) { { "SV_VertexID", "gl_VertexID" }, { "SV_InstanceID", "gl_InstanceID" }, };
130 
131  builtinVertexOutputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
132  builtinGeometryInputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
133  builtinGeometryOutputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
134  builtinPixelInputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
135  builtinPixelOutputs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
136 
137  // Register defaults Semantics with ShaderModel
138  if (shaderModel < ShaderModel.Model40)
139  {
140  builtinVertexOutputs.Add("POSITION", "gl_Position");
141  builtinVertexOutputs.Add("PSIZE", "gl_PointSize");
142 
143  builtinGeometryInputs.Add("PSIZE", "gl_PointSize");
144 
145  builtinGeometryOutputs.Add("PSIZE", "gl_PointSize");
146 
147  builtinPixelInputs.Add("VPOS", "gl_FragCoord");
148  builtinPixelInputs.Add("VFACE", gl_FrontFacing);
149  builtinPixelInputs.Add("POSITION", "gl_FragCoord");
150 
151  builtinPixelOutputs.Add("DEPTH", "gl_FragDepth");
152  builtinPixelOutputs.Add("COLOR", "gl_FragData[]");
153  }
154  else
155  {
156  builtinVertexOutputs.Add("SV_Position", "gl_Position");
157  builtinVertexOutputs.Add("SV_ClipDistance", "gl_ClipDistance[]");
158 
159  builtinGeometryInputs.Add("SV_POSITION", "gl_Position");
160  builtinGeometryInputs.Add("SV_ClipDistance", "gl_ClipDistance[]");
161  builtinGeometryInputs.Add("SV_PrimitiveID", "gl_PrimitiveIDIn");
162 
163  builtinGeometryOutputs.Add("SV_POSITION", "gl_Position");
164  builtinGeometryOutputs.Add("SV_ClipDistance", "gl_ClipDistance[]");
165  builtinGeometryOutputs.Add("SV_RenderTargetArrayIndex", "gl_Layer");
166 
167  builtinPixelInputs.Add("SV_Position", "gl_FragCoord");
168  builtinPixelInputs.Add("SV_IsFrontFace", "gl_FrontFacing");
169  builtinPixelInputs.Add("SV_ClipDistance", "gl_ClipDistance[]");
170 
171  builtinPixelOutputs.Add("SV_Depth", "gl_FragDepth");
172  builtinPixelOutputs.Add("SV_Target", "gl_FragData[]");
173  }
174 
175  builtinGlslTypes = new Dictionary<string, TypeBase>(StringComparer.CurrentCultureIgnoreCase)
176  {
177  { "gl_ClipDistance", ScalarType.Float}, // array
178  { "gl_FragCoord", VectorType.Float4},
179  { "gl_FragDepth", ScalarType.Float},
180  { "gl_FragColor", VectorType.Float4},
181  { "gl_FragData", VectorType.Float4},
182  { "gl_FrontFacing", ScalarType.Bool},
183  { "gl_InstanceID", ScalarType.Int },
184  { "gl_InvocationID", ScalarType.Int},
185  { "gl_Layer", ScalarType.Int},
186  { "gl_NumSamples", ScalarType.Int},
187  { "gl_PatchVerticesIn", ScalarType.Int},
188  { "gl_PointCoord", VectorType.Float2},
189  { "gl_PointSize", ScalarType.Float},
190  { "gl_Position", VectorType.Float4},
191  { "gl_PrimitiveID", ScalarType.Int},
192  { "gl_PrimitiveIDIn", ScalarType.Int},
193  { "gl_SampleID", ScalarType.Int},
194  { "gl_SampleMask", ScalarType.Int}, // array
195  { "gl_SampleMaskIn", ScalarType.Int}, // array
196  { "gl_SamplePosition", VectorType.Float2},
197  { "gl_TessCoord", VectorType.Float3},
198  { "gl_VertexID", ScalarType.Int},
199  { "gl_ViewportIndex", ScalarType.Int},
200  };
201  }
202 
203  functionMapping = new Dictionary<string, string> {
204  { "ddx", "dFdx" },
205  { "ddy", "dFdy" },
206  { "fmod", "mod" },
207  { "frac", "fract" },
208  { "lerp", "mix" },
209  { "rsqrt", "inversesqrt" },
210  { "atan2", "atan" },
211  { "saturate", "clamp" },
212  //{ "D3DCOLORtoUBYTE4", "ivec4" },
213  };
214  }
215 
216  #endregion
217 
218  #region Public Properties
219 
220  /// <summary>
221  /// Gets or sets a value indicating wether Z projection coordinates will be remapped from [0;1] to [-1;1] at end of vertex shader.
222  /// </summary>
223  public bool ViewFrustumRemap { get; set; }
224 
225  /// <summary>
226  /// Gets or sets a value indicating whether this instance is point sprite shader.
227  /// </summary>
228  /// <value>
229  /// <c>true</c> if this instance is point sprite shader; otherwise, <c>false</c>.
230  /// </value>
231  public bool IsPointSpriteShader { get; set; }
232 
233  /// <summary>
234  /// Gets or sets a value indicating whether [no fix for mul for matrix].
235  /// </summary>
236  /// <value>
237  /// <c>true</c> if [no fix for mul for matrix]; otherwise, <c>false</c>.
238  /// </value>
239  public bool NoSwapForBinaryMatrixOperation { get; set; }
240 
241  /// <summary>
242  /// Gets or sets a value indicating whether [no implicit layout].
243  /// </summary>
244  /// <value>
245  /// <c>true</c> if [no implicit layout]; otherwise, <c>false</c>.
246  /// </value>
247  public bool UseBindingLayout { get; set; }
248 
249  /// <summary>
250  /// Gets or sets a value indicating whether [use builtin semantic].
251  /// </summary>
252  /// <value>
253  /// <c>true</c> if [use builtin semantic]; otherwise, <c>false</c>.
254  /// </value>
255  public bool UseBuiltinSemantic { get; set; }
256 
257  /// <summary>
258  /// Gets or sets a value indicating whether [use explicit layout position].
259  /// </summary>
260  /// <value>
261  /// <c>true</c> if [use explicit layout position]; otherwise, <c>false</c>.
262  /// </value>
263  public bool UseLocationLayout { get; set; }
264 
265  /// <summary>
266  /// Gets or sets a value indicating whether texture name will be [texture] or [texture]_[sampler] for DX10 texture objects conversion.
267  /// </summary>
268  public bool UseOnlyTextureName { get; set; }
269 
270  /// <summary>
271  /// Gets or sets a value indicating whether [use semantic name].
272  /// </summary>
273  /// <value>
274  /// <c>true</c> if [use semantic name]; otherwise, <c>false</c>.
275  /// </value>
276  public bool UseSemanticForVariable { get; set; }
277 
278  /// <summary>
279  /// Gets or sets a value indicating whether [use semantic for location].
280  /// </summary>
281  /// <value>
282  /// <c>true</c> if [use semantic for location]; otherwise, <c>false</c>.
283  /// </value>
284  public bool UseSemanticForLocation { get; set; }
285 
286  /// <summary>
287  /// Gets or sets a value indicating whether [use interface for in out].
288  /// </summary>
289  /// <value><c>true</c> if [use interface for in out]; otherwise, <c>false</c>.</value>
290  public bool UseInterfaceForInOut { get; set; }
291 
292  /// <summary>
293  /// Gets the map config.
294  /// </summary>
295  /// <value>
296  /// The map config.
297  /// </value>
298  public Dictionary<string, VariableLayoutRule> VariableLayouts { get; private set; }
299 
300  /// <summary>
301  /// Gets the constant buffer layouts.
302  /// </summary>
303  /// <value>
304  /// The constant buffer layouts.
305  /// </value>
306  public Dictionary<string, ConstantBufferLayoutRule> ConstantBufferLayouts { get; private set; }
307 
308  /// <summary>
309  /// Gets or sets the map rules.
310  /// </summary>
311  /// <value>
312  /// The map rules.
313  /// </value>
314  public Dictionary<string, MapRule> MapRules { get; private set; }
315 
316  /// <summary>
317  /// Gets or sets a value indicating whether to keep array initializers for uniforms.
318  /// </summary>
319  /// <value>
320  /// true if keep uniform array initializers, false if not.
321  /// </value>
322  public bool KeepUniformArrayInitializers { get; set; }
323 
324  /// <summary>
325  /// Gets or sets a flag specifying whether compatibility profile is used for texture functions.
326  /// As an example, with compatibility on, texture() might become texture2D().
327  /// </summary>
328  /// <value>
329  /// true if texture compatibility profile is enabled, false if not.
330  /// </value>
331  public bool TextureFunctionsCompatibilityProfile { get; set; }
332 
333  /// <summary>
334  ///
335  /// </summary>
336  public bool KeepConstantBuffer { get; set; }
337 
338  /// <summary>
339  /// Gets or sets a value indicating whether to keep array initializers.
340  /// </summary>
341  public bool KeepNonUniformArrayInitializers { get; set; }
342 
343  /// <summary>
344  /// Gets or sets a value indicating whether to unroll the loops with the [unroll] annotation.
345  /// </summary>
346  public bool UnrollForLoops { get; set; }
347 
348  #endregion
349 
350  #region Properties
351 
352  /// <summary>
353  /// Gets or sets the current function being parsed.
354  /// </summary>
355  /// <value>
356  /// The current function.
357  /// </value>
358  private MethodDeclaration CurrentFunction { get; set; }
359 
360  /// <summary>
361  /// Gets a value indicating whether this instance is in entry point.
362  /// </summary>
363  /// <value>
364  /// <c>true</c> if this instance is in entry point; otherwise, <c>false</c>.
365  /// </value>
366  private bool IsInEntryPoint { get { return CurrentFunction != null && CurrentFunction.Name.Text == entryPointName; } }
367 
368  #endregion
369 
370  #region Public Methods and Operators
371 
372  /// <summary>
373  /// Prepares the specified shader for glsl to hlsl conversion (before type inference analysis).
374  /// </summary>
375  /// <param name="shader">
376  /// The shader.
377  /// </param>
378  public static void Prepare(Shader shader)
379  {
380  // Replace all Half types to float, as there are no equivalent in glsl
381  // This will force the type inference analysis to use float instead of half
382  SearchVisitor.Run(
383  shader,
384  node =>
385  {
386  if (node.Equals(ScalarType.Half))
387  return ScalarType.Float;
388 
389  // Transform half vectors to float vectors
390  var typeBase = node as TypeBase;
391  if (typeBase != null)
392  {
393  var vectorType = typeBase.ResolveType() as VectorType;
394  if (vectorType != null)
395  {
396  var subType = vectorType.Type.ResolveType();
397  if (subType == ScalarType.Half)
398  typeBase.TypeInference.TargetType = TypeBase.CreateWithBaseType(vectorType, ScalarType.Float);
399  }
400  }
401 
402  return node;
403  });
404  }
405 
406  /// <summary>
407  /// Runs the convertor on the specified parser result.
408  /// </summary>
409  /// <param name="parserResultIn">The parser result.</param>
410  public void Run(ParsingResult parserResultIn)
411  {
412  parserResult = parserResultIn;
413  shader = parserResultIn.Shader;
414 
415  // Transform typedef with inline declaration to separate declaration + typedef
416  // in order for the strip visitor to work
417  SplitTypeDefs();
418 
419  // Find entry point
420  entryPoint = shader.Declarations.OfType<MethodDefinition>().FirstOrDefault(x => x.Name.Text == entryPointName);
421 
422  if (entryPoint == null)
423  throw new ArgumentException(string.Format("Could not find entry point named {0}", entryPointName));
424 
425  // Transform multiple variable declaration to single
426  TransformGlobalMultipleVariableToSingleVariable();
427 
428  // Gather all samplers and create new samplers
429  // Strips unused code
430  this.GenerateSamplerMappingAndStrip();
431 
432  // Look for global uniforms used as global temp variable
433  globalUniformVisitor = new GlobalUniformVisitor(shader);
434  globalUniformVisitor.Run((MethodDefinition)entryPoint);
435 
436  var writer = new HlslWriter();
437  writer.Visit(shader);
438  var text = writer.Text;
439 
440  var castVisitor = new CastAnalysis(parserResult);
441  castVisitor.Run();
442 
443  // This the shader
444  Visit(shader);
445 
446  // Remove Default parameters for all function
447  RemoveDefaultParametersForMethods();
448 
449  // Transform all types to glsl types
450  TranformToGlslTypes();
451 
452  // Rename variable using a glsl keyword
453  RenameGlslKeywords();
454 
455  // Rebind all renamed variables
456  RebindVariableReferenceExpressions();
457 
458  // Order first all non-method declarations and then after method declarations
459  var declarations = shader.Declarations.Where(declaration => !(declaration is MethodDeclaration)).ToList();
460  declarations.AddRange(shader.Declarations.OfType<MethodDeclaration>());
461  shader.Declarations = declarations;
462 
463  }
464 
465  #endregion
466 
467  #region Methods
468 
469  /// <summary>
470  /// Visits the specified variable.
471  /// </summary>
472  /// <param name="variable">
473  /// The variable.
474  /// </param>
475  [Visit]
476  protected Node Visit(Variable variable)
477  {
478  var isInMethod = !shader.Declarations.Contains(variable);
479 
480  // Static variable are allowed inside HLSL functions
481  // but only at global scope for glsl
482  // TODO check if removing the static modifier is enough or we need to move the variable at the toplevel scope (a bit more harder to implement)
483  if (CurrentFunction != null && variable.Qualifiers.Contains(Ast.Hlsl.StorageQualifier.Static))
484  variable.Qualifiers.Values.Remove(Ast.Hlsl.StorageQualifier.Static);
485 
486  // Because const qualifier in HLSL is way too permissive, we need to remove it for GLSL
487  // Remove only const qualifiers inside methods
488  if (isInMethod && variable.Qualifiers.Contains(Ast.StorageQualifier.Const))
489  variable.Qualifiers.Values.Remove(Ast.StorageQualifier.Const);
490 
491  Visit((Node)variable);
492 
493  // Set the Type of a variable by using the resolve type
494  if (variable.Type.TypeInference.Declaration is Typedef)
495  {
496  var typeDefType = variable.Type.ResolveType();
497  if (typeDefType is StructType)
498  {
499  variable.Type = new TypeName(typeDefType.Name) { TypeInference = { Declaration = (IDeclaration)typeDefType, TargetType = typeDefType } };
500  }
501  else
502  {
503  variable.Type = typeDefType;
504  }
505  }
506 
507  if (variable.Type is ArrayType)
508  {
509  if (variable.InitialValue is MethodInvocationExpression && !KeepNonUniformArrayInitializers)
510  {
511  if (isInMethod) // inside a method
512  {
513  var arrayInit = variable.InitialValue as MethodInvocationExpression;
514  if (arrayInit.Target is IndexerExpression) // HACK: this checks that it is an initialization. It is a hack because the GLSL grammar was mapped into the hlsl one
515  {
516  // build the statement list
517  var statements = new StatementList();
518  statements.Add(new DeclarationStatement(variable));
519  for (int i = 0; i < arrayInit.Arguments.Count; ++i)
520  {
521  var statement = new ExpressionStatement(new AssignmentExpression(AssignmentOperator.Default, new IndexerExpression(new VariableReferenceExpression(variable.Name), new LiteralExpression(i)), arrayInit.Arguments[i]));
522  statements.Add(statement);
523  }
524 
525  // patch the variable
526  variable.InitialValue = null;
527 
528  return statements;
529  }
530  }
531  else if (!isInMethod && !IsUniformLike(variable)) // non-uniform variable oustide a method
532  {
533  variable.InitialValue = null;
534  }
535  }
536  }
537 
538  return variable;
539  }
540 
541  /// <summary>
542  /// Visits the specified function.
543  /// </summary>
544  /// <param name="function">The function.</param>
545  [Visit]
546  protected void Visit(MethodDefinition function)
547  {
548  // Enter this function
549  CurrentFunction = function;
550 
551 
552  // Convert HLSL "in out" qualifier to "inout" qualifier
553  foreach (var arg in function.Parameters)
554  {
555  if (arg.Qualifiers.Contains(Ast.ParameterQualifier.Out) && arg.Qualifiers.Contains(Ast.ParameterQualifier.In))
556  {
557  arg.Qualifiers.Values.Remove(Ast.ParameterQualifier.Out);
558  arg.Qualifiers.Values.Remove(Ast.ParameterQualifier.In);
559  arg.Qualifiers.Values.Add(Ast.ParameterQualifier.InOut);
560  }
561  }
562 
563  if (function == entryPoint)
564  PrepareVisitEntryPoint(function); // Prepare visit of entry point
565  else
566  function.Qualifiers.Values.Clear(); // Remove semantics from function indirectly used by entrypoint
567 
568  // Convert function return type
569  // Visit all subnodes of this function
570  Visit((Node)function);
571 
572  // For entry point restore arguments/declcontext
573  if (function == entryPoint)
574  PostVisitEntryPoint(function);
575 
576  // Remove uniform parameters
577  foreach (var modifier in function.Parameters.Select(variable => variable.Qualifiers).Where(modifier => modifier.Contains(Ast.StorageQualifier.Uniform)))
578  modifier.Values.Remove(Ast.StorageQualifier.Uniform);
579 
580  // For GeometryShader, remove StreamType parameters
581  RemoveStreamTypeFromMethodDefinition(function);
582 
583  // Clear current function viside
584  CurrentFunction = null;
585  }
586 
587  /// <summary>
588  /// Prepares the visit of entry point.
589  /// </summary>
590  /// <param name="function">The entry point function.</param>
591  protected void PrepareVisitEntryPoint(MethodDefinition function)
592  {
593  inputs.Clear();
594  outputs.Clear();
595 
596  // Make a copy of arguments
597  // var savedDeclarationContext = function.Declarations.ToList();
598  foreach (var arg in function.Parameters)
599  {
600  if (arg.Qualifiers.Contains(Ast.ParameterQualifier.Out) || arg.Qualifiers.Contains(Ast.ParameterQualifier.InOut))
601  {
602  outputs.Add(arg);
603  }
604  else
605  {
606  inputs.Add(arg);
607 
608  // Process and convert GS input layout type
609  foreach (var qualifier in arg.Qualifiers.OfType<Ast.ParameterQualifier>())
610  {
611  switch ((string)qualifier.Key)
612  {
613  case "triangleadj":
614  geometryLayoutInput = "triangles_adjacency";
615  break;
616  case "triangle":
617  geometryLayoutInput = "triangles";
618  break;
619  case "lineadj":
620  geometryLayoutInput = "lines_adjacency";
621  break;
622  case "line":
623  geometryLayoutInput = "lines";
624  break;
625  case "point":
626  geometryLayoutInput = "points";
627  break;
628  }
629 
630  if (geometryLayoutInput != null)
631  {
632  geometryInputParameter = arg;
633  }
634  }
635  }
636  }
637 
638 
639  // ------------------------------------------------
640  // Check the type of the output for pixel shaders
641  // If glFragData has multiple types, than we need to output a
642  // new output type for glFragData.
643  // ------------------------------------------------
644 
645  if (pipelineStage == PipelineStage.Pixel)
646  {
647  int countDifferentType = 0;
648 
649  foreach (var output in outputs)
650  {
651  var outputType = output.Type.ResolveType();
652  if (outputType is StructType)
653  {
654  countDifferentType += GetMembers((StructType)outputType).Select(fieldRef => fieldRef.Field).Count(field => this.CheckFragDataOutputType(field.Semantic(), field.Type.ResolveType()));
655  }
656  else
657  {
658  if (CheckFragDataOutputType(output.Semantic(), outputType))
659  countDifferentType++;
660  }
661  }
662 
663  var returnType = function.ReturnType.ResolveType();
664  var returnStructType = returnType as StructType;
665  if (returnStructType != null)
666  {
667  countDifferentType += GetMembers(returnStructType).Select(fieldRef => fieldRef.Field).Count(field => this.CheckFragDataOutputType(field.Semantic(), field.Type.ResolveType()));
668  }
669  else if (function.Semantic() != null)
670  {
671  if (CheckFragDataOutputType(function.Semantic(), returnType))
672  countDifferentType++;
673  }
674 
675  isPixelShaderOutputFragDataMuliType = countDifferentType > 0;
676  }
677  }
678 
679  private bool CheckFragDataOutputType(Semantic inputSemantic, TypeBase type)
680  {
681  if (inputSemantic == null)
682  return false;
683 
684  TypeBase newFieldType;
685  int semanticIndex = 0;
686  var semantic = ResolveSemantic(inputSemantic, type, false, "tmptmp", out newFieldType, out semanticIndex, inputSemantic.Span);
687  if (semantic.Name.Text.StartsWith("gl_fragdata", StringComparison.InvariantCultureIgnoreCase) && (newFieldType != type || type is ArrayType))
688  {
689  return true;
690  //// Generate only fragdata when whe basetype is completly changing
691  //// TODO: improve handling gl_fragdata: Current code is not robust.
692  //var baseElementType = type is ArrayType ? ((ArrayType)type).Type.ResolveType() : type;
693  //var baseNewElementType = newFieldType is ArrayType ? ((ArrayType)newFieldType).Type.ResolveType() : newFieldType;
694 
695  //// Get type of the element
696  //baseElementType = TypeBase.GetBaseType(baseElementType);
697  //baseNewElementType = TypeBase.GetBaseType(baseNewElementType);
698 
699  //return (baseElementType != baseNewElementType);
700  }
701  return false;
702  }
703 
704  /// <summary>
705  /// Visits the entry point.
706  /// </summary>
707  /// <param name="function">The entry point function.</param>
708  protected void PostVisitEntryPoint(MethodDefinition function)
709  {
710  int inputSemanticLocation = 0;
711  int outputSemanticLocation = 0;
712 
713  // For structure in input, make a local copy
714  foreach (var variable in this.inputs)
715  {
716  var structType = variable.Type.ResolveType() as StructType;
717  if (structType != null)
718  {
719  bool semanticFound = false;
720  foreach (var fieldRef in GetMembers(structType))
721  {
722  var field = fieldRef.Field;
723 
724  var semantic = field.Semantic();
725  if (semantic != null)
726  {
727  var fieldType = field.Type.ResolveType();
728  var variableFromSemantic = this.BindLocation(semantic, fieldType, true, fieldRef.FieldNamePath, ref inputSemanticLocation, variable.Span);
729 
730  // Link to the original variable
731  // var variableSemanticRef = new VariableReferenceExpression(variableFromSemantic.Name) { TypeInference = { Declaration = variableFromSemantic } };
732 
733  function.Body.Insert(
734  0,
737  AssignmentOperator.Default, fieldRef.GetMemberReference(new VariableReferenceExpression(variable.Name)),
738  this.CastSemanticToReferenceType(variableFromSemantic.Name, fieldType, variableFromSemantic))) { Span = variable.Span });
739  semanticFound = true;
740  }
741  }
742 
743  if (semanticFound)
744  {
745  // No modifiers for structure inlined in the code
746  variable.Qualifiers = Qualifier.None;
747  function.Body.Statements.Insert(0, new DeclarationStatement(variable) { Span = variable.Span });
748  }
749  }
750  else
751  {
752  var semantic = variable.Semantic();
753  if (semantic != null)
754  this.BindLocation(semantic, variable.Type.ResolveType(), true, variable.Name, ref inputSemanticLocation, variable.Span);
755  }
756  }
757 
758  // For structure in output, declare a local variable
759  foreach (var variable in this.outputs)
760  {
761  var structType = variable.Type.ResolveType() as StructType;
762  if (structType != null)
763  {
764  // No modifiers for structure inlined in the code
765  variable.Qualifiers = Qualifier.None;
766  function.Body.Statements.Insert(0, new DeclarationStatement(variable));
767 
768  var statementList = new StatementList();
769 
770  var lastStatement = function.Body.Statements.LastOrDefault();
771 
772  ReturnStruct(structType, new VariableReferenceExpression(variable.Name) { Span = lastStatement != null ? lastStatement.Span : new SourceSpan() }, statementList);
773 
774  function.Body.Statements.Add(statementList);
775  }
776  }
777 
778  // Process return type
779  var returnType = function.ReturnType.ResolveType();
780  var returnStructType = returnType as StructType;
781  if (returnStructType != null)
782  {
783  foreach (var fieldRef in GetMembers(returnStructType))
784  {
785  var field = fieldRef.Field;
786  BindLocation(field.Semantic(), field.Type.ResolveType(), false, field.Name, ref outputSemanticLocation, function.ReturnType.Span);
787  }
788  }
789  else if (function.Semantic() != null)
790  {
791  var semantic = function.Semantic();
792  BindLocation(semantic, returnType, false, null, ref outputSemanticLocation, semantic.Span);
793  }
794 
795  // Set Location for each output
796  if (pipelineStage == PipelineStage.Geometry)
797  {
798  foreach (var variable in shader.Declarations.OfType<Variable>())
799  {
800  if (variable.Qualifiers.Contains(Ast.ParameterQualifier.Out))
801  {
802  BindLocation(variable.Semantic(), variable.Type.ResolveType(), false, variable.Name, ref outputSemanticLocation, variable.Span);
803  }
804  }
805  }
806  else
807  {
808  foreach (var outputVariable in outputs)
809  {
810  BindLocation(outputVariable.Semantic(), outputVariable.Type.ResolveType(), false, outputVariable.Name, ref outputSemanticLocation, outputVariable.Span);
811  }
812  }
813 
814  // Process parameters
815  for (int i = 0; i < function.Parameters.Count; ++i)
816  {
817  var variable = function.Parameters[i];
818  var modifier = variable.Qualifiers;
819  if (modifier.Contains(Ast.StorageQualifier.Uniform))
820  {
821  function.Parameters.RemoveAt(i--);
822  ScopeStack.Peek().RemoveDeclaration(variable);
823 
824  if (!shader.Declarations.Contains(variable))
825  {
826  // Generate name by appending _uniform and _1, _2 etc... if already existing
827  var variableNameBase = variable.Name;
828  variable.Name.Text += "_uniform";
829  int variableNameIndex = 1;
830  while (FindDeclaration(variable.Name) != null)
831  variable.Name.Text = variableNameBase + "_" + variableNameIndex++;
832 
833  AddGlobalDeclaration(variable);
834  }
835  }
836  }
837 
838  // Fix variable references that were transform to local variable
839  // This is not ideal, as we should instead perform a pre-pass to detect these variables
840  // and patch them after the pre-pass
841  // The problem is that ConvertReferenceToSemantics is working only if a variable is modified
842  // first and then used, but if a variable is used, and then modified, ConvertReferenceToSemantics
843  // will not modify the previous 'local' variable.
844  // This code is a workaround. A refactoring of the whole process would be more adequate but requires
845  // more changes to the overall logic that we can't really afford now.
846  SearchVisitor.Run(
847  function,
848  node =>
849  {
850  var varRefExpr = node as VariableReferenceExpression;
851  if (varRefExpr != null)
852  {
853  var variable = FindDeclaration(varRefExpr.Name) as Variable;
854  if (variable != null)
855  {
856  Variable newVariable;
857  inputAssignment.TryGetValue(variable, out newVariable);
858 
859  if (newVariable != null)
860  {
861  return new VariableReferenceExpression(newVariable);
862  }
863  }
864  }
865  return node;
866  });
867  }
868 
869 
870  /// <summary>
871  /// Visits the specified cast expression.
872  /// </summary>
873  /// <param name="castExpression">The cast expression.</param>
874  /// <returns>A transformed cast expression</returns>
875  [Visit]
876  protected Expression Visit(CastExpression castExpression)
877  {
878  Visit((Node)castExpression);
879 
880  var targetType = castExpression.Target.TypeInference.TargetType;
881 
882  // If there is a cast from an integer 0 to a struct, than remove the cast for GLSL, as it is not supported
883  if (targetType is StructType && castExpression.From is LiteralExpression)
884  {
885  var literalExpression = (LiteralExpression)castExpression.From;
886  if (literalExpression.Value != null)
887  {
888  var toStringValue = literalExpression.Value.ToString().Trim();
889  if (toStringValue == "0")
890  return null;
891  }
892  }
893 
894  // Remove cast for literal integer/float by generating a proper literal
895  if (targetType == ScalarType.Float && castExpression.From is LiteralExpression)
896  {
897  var literalExpression = (LiteralExpression)castExpression.From;
898  literalExpression.Value = Convert.ChangeType(literalExpression.Value, typeof(float));
899  return literalExpression;
900  }
901 
902  var castByMethod = new MethodInvocationExpression(new TypeReferenceExpression(castExpression.Target), castExpression.From);
903 
904  targetType = castExpression.TypeInference.TargetType;
905  if (targetType != null)
906  castByMethod.TypeInference.TargetType = targetType;
907 
908  CheckCastMethod(castByMethod);
909 
910  return castByMethod;
911  }
912 
913  /// <summary>
914  /// Visits the specified statement.
915  /// </summary>
916  /// <param name="statement">The statement.</param>
917  /// <returns>A transformed statement</returns>
918  [Visit]
919  protected Statement Visit(Statement statement)
920  {
921  Statement newStatement = null;
922 
923  var expressionStatement = statement as ExpressionStatement;
924  if (expressionStatement != null)
925  {
926  var methodInvocationExpression = expressionStatement.Expression as MethodInvocationExpression;
927  if (methodInvocationExpression != null)
928  {
929  var methodVar = methodInvocationExpression.Target as VariableReferenceExpression;
930  if (methodVar != null)
931  {
932  newStatement = VisitStatementAsFunctionInvocation(statement, methodInvocationExpression, methodVar);
933  }
934  else
935  {
936  var memberReferenceExpression = methodInvocationExpression.Target as MemberReferenceExpression;
937  if (memberReferenceExpression != null)
938  {
939  newStatement = VisitStatementAsMemberInvocation(statement, methodInvocationExpression, memberReferenceExpression);
940  }
941  }
942  }
943  else
944  {
945  var assignExpression = expressionStatement.Expression as AssignmentExpression;
946  if (assignExpression != null)
947  {
948  newStatement = VisitStatementAsAssignExpression(statement, assignExpression);
949  }
950  }
951  }
952 
953  return newStatement ?? (Statement)this.Visit((Node)statement);
954  }
955 
956  /// <summary>
957  /// Visits a statement that is a function invocation.
958  /// </summary>
959  /// <param name="statement">The statement.</param>
960  /// <param name="methodInvocationExpression">The function invocation expression.</param>
961  /// <param name="methodVar">The name of the function.</param>
962  /// <returns></returns>
964  {
965  var methodName = methodVar.Name;
966 
967  switch (methodName)
968  {
969  case "clip":
970  if (methodInvocationExpression.Arguments.Count == 1)
971  {
972  Expression conditionExpression;
973 
974  if (!methodInvocationHandled.ContainsKey(methodInvocationExpression))
975  methodInvocationHandled.Add(methodInvocationExpression, true);
976 
977  Visit((Node)statement);
978 
979  var clipArgType = methodInvocationExpression.Arguments[0].TypeInference.TargetType;
980 
981  bool isSingleValue = clipArgType is ScalarType; // || clipArgType.Generics == null);
982  if (isSingleValue)
983  conditionExpression = new BinaryExpression(
984  BinaryOperator.Less, ConvertToSafeExpressionForBinary(methodInvocationExpression.Arguments[0]), new LiteralExpression(ScalarType.IsInteger(clipArgType) ? (object)0 : 0.0f));
985  else
986  {
987  var castToZero = new MethodInvocationExpression(new TypeReferenceExpression(clipArgType), new LiteralExpression(0));
988  var lessThan = new MethodInvocationExpression("lessThan", methodInvocationExpression.Arguments[0], castToZero);
989  var methodAll = new MethodInvocationExpression("all", lessThan);
990  conditionExpression = methodAll;
991  }
992 
993  return new IfStatement { Condition = conditionExpression, Then = new ExpressionStatement(new KeywordExpression("discard")) };
994  }
995 
996  break;
997  case "sincos":
998 
999  if (methodInvocationExpression.Arguments.Count == 3)
1000  {
1001  if (!methodInvocationHandled.ContainsKey(methodInvocationExpression))
1002  methodInvocationHandled.Add(methodInvocationExpression, true);
1003  Visit((Node)statement);
1004 
1005  var sinAssign =
1006  new ExpressionStatement(
1008  AssignmentOperator.Default, methodInvocationExpression.Arguments[1], new MethodInvocationExpression("sin", methodInvocationExpression.Arguments[0])));
1009 
1010  var cosAssign =
1011  new ExpressionStatement(
1013  AssignmentOperator.Default, methodInvocationExpression.Arguments[2], new MethodInvocationExpression("cos", methodInvocationExpression.Arguments[0])));
1014 
1015  return new StatementList(sinAssign, cosAssign);
1016  }
1017 
1018  break;
1019  }
1020 
1021  return null;
1022  }
1023 
1024  /// <summary>
1025  /// Visits a statement that is a member invocation.
1026  /// </summary>
1027  /// <param name="statement">The statement.</param>
1028  /// <param name="methodInvocationExpression">The method invocation expression.</param>
1029  /// <param name="memberReferenceExpression">The member reference expression.</param>
1030  /// <returns>A new statement if handled, null otherwise</returns>
1031  protected Statement VisitStatementAsMemberInvocation(Statement statement, MethodInvocationExpression methodInvocationExpression, MemberReferenceExpression memberReferenceExpression)
1032  {
1033  if (memberReferenceExpression.Member == "GetDimensions")
1034  {
1035  var textureRef = memberReferenceExpression.Target as VariableReferenceExpression;
1036  var variableTexture = this.FindGlobalVariableFromExpression(textureRef);
1037 
1038  if (variableTexture == null)
1039  {
1040  parserResult.Error("Unable to find target variable for expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1041  return null;
1042  }
1043 
1044  var glslSampler = GetGLSampler(null, variableTexture, false);
1045 
1046  if (glslSampler == null)
1047  {
1048  parserResult.Error("Unable to find matching sampler for GetDimensions() for expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1049  return null;
1050  }
1051 
1052  // Convert texture.GetDimensions(x, y) into
1053  // {
1054  // var texSize = textureSize(texture);
1055  // x = texSize.x;
1056  // y = texSize.y;
1057  // }
1058  var resultBlock = new BlockStatement();
1059 
1060  var textureSizeCall = new MethodInvocationExpression(new VariableReferenceExpression("textureSize"));
1061  textureSizeCall.Arguments.Add(new VariableReferenceExpression(glslSampler.Name));
1062  textureSizeCall.Arguments.Add(new LiteralExpression(0));
1063 
1064  // TODO: Support for sampler size other than 2D
1065  var textureSizeVariable = new Variable(VectorType.Int2, "tempTextureSize", textureSizeCall);
1066  resultBlock.Statements.Add(new DeclarationStatement(textureSizeVariable));
1067  resultBlock.Statements.Add(
1068  new ExpressionStatement(
1070  AssignmentOperator.Default,
1071  methodInvocationExpression.Arguments[0],
1072  new MemberReferenceExpression(new VariableReferenceExpression(textureSizeVariable.Name), "x"))));
1073  resultBlock.Statements.Add(
1074  new ExpressionStatement(
1076  AssignmentOperator.Default,
1077  methodInvocationExpression.Arguments[1],
1078  new MemberReferenceExpression(new VariableReferenceExpression(textureSizeVariable.Name), "y"))));
1079 
1080  return resultBlock;
1081  }
1082 
1083  return null;
1084  }
1085 
1087  {
1088  var indexerExpression = assignmentExpression.Target as IndexerExpression;
1089  if (NoSwapForBinaryMatrixOperation && indexerExpression != null)
1090  {
1091  // Collect all indices in the order of the declaration
1092  var targetIterator = indexerExpression.Target;
1093  var indices = new List<Expression> { indexerExpression.Index };
1094  while (targetIterator is IndexerExpression)
1095  {
1096  indices.Add(((IndexerExpression)targetIterator).Index);
1097  targetIterator = ((IndexerExpression)targetIterator).Target;
1098  }
1099 
1100  // Check that index apply to an array variable
1101  var variableReferenceExpression = targetIterator as VariableReferenceExpression;
1102  if (variableReferenceExpression != null)
1103  {
1104  var variable = FindDeclaration(variableReferenceExpression.Name) as Variable;
1105 
1106  // If array is a multidimension array
1107  var variableType = variable != null ? variable.Type.ResolveType() : null;
1108  var matrixType = variableType as MatrixType;
1109 
1110  if (matrixType != null)
1111  {
1112  if (indices.Count == 2)
1113  {
1114  IndexerExpression nextExpression = null;
1115 
1116  // float4x3[0][1] -> mat4x3[1][0]
1117  for (int i = 0; i < indices.Count; i++)
1118  {
1119  nextExpression = nextExpression == null ? new IndexerExpression(variableReferenceExpression, indices[i]) : new IndexerExpression(nextExpression, indices[i]);
1120  }
1121 
1122  assignmentExpression.Target = nextExpression;
1123  }
1124  else
1125  {
1126  // matrixType.ColumnCount
1127  var matrixElementType = matrixType.Type.ResolveType() as ScalarType;
1128  var matrixRowType = new VectorType(matrixElementType, matrixType.ColumnCount);
1129 
1130  // Convert mat3x4[0] = ...; into
1131  // {
1132  // var local = ...;
1133  // mat3x4[0][0] = local.x;
1134  // mat3x4[0][1] = local.y;
1135  // mat3x4[0][2] = local.z;
1136  // mat3x4[0][3] = local.w;
1137  // }
1138  var resultBlock = new BlockStatement();
1139 
1140  // need to call the visitor on the value here since Visit(AssignmentExpression ) won't be called afterwards (non null function's return).
1141  assignmentExpression.Value = (Expression)VisitDynamic(assignmentExpression.Value);
1142 
1143  var localResult = new Variable(matrixRowType, "_localmat_", assignmentExpression.Value);
1144  resultBlock.Statements.Add(new DeclarationStatement(localResult));
1145 
1146  for (int i = 0; i < matrixType.ColumnCount; i++)
1147  {
1148  var targetExpression = new IndexerExpression(new IndexerExpression(indexerExpression.Target, new LiteralExpression(i)), indexerExpression.Index);
1149  var valueExpression = new IndexerExpression(new VariableReferenceExpression("_localmat_"), new LiteralExpression(i));
1150  var assignRowCol = new AssignmentExpression(AssignmentOperator.Default, targetExpression, valueExpression);
1151  resultBlock.Statements.Add(new ExpressionStatement(assignRowCol));
1152  }
1153  return resultBlock;
1154  }
1155  }
1156  }
1157  }
1158 
1159  return null;
1160  }
1161 
1162 
1163 
1164  /// <summary>
1165  /// Visits the specified method invocation expression.
1166  /// </summary>
1167  /// <param name="methodInvocationExpression">The method invocation expression.</param>
1168  /// <returns>
1169  /// A transformed method invocation expression.
1170  /// </returns>
1171  [Visit]
1172  protected Expression Visit(MethodInvocationExpression methodInvocationExpression)
1173  {
1174  Visit((Node)methodInvocationExpression);
1175 
1176  // If method is already handled
1177  if (methodInvocationHandled.ContainsKey(methodInvocationExpression))
1178  return methodInvocationExpression;
1179 
1180  MethodDeclaration methodDeclaration = null;
1181 
1182  // Transform various method calls to match OpenGL specs.
1183  var methodVar = methodInvocationExpression.Target as VariableReferenceExpression;
1184  if (methodVar != null)
1185  {
1186  var methodName = methodVar.Name;
1187  methodDeclaration = methodVar.TypeInference.Declaration as MethodDeclaration;
1188 
1189  // When a method is calling a typedef, use the type of the type def as a TypeReference instead of a VariableReference
1190  if (methodInvocationExpression.TypeInference.Declaration is Typedef)
1191  {
1192  methodInvocationExpression.Target = new TypeReferenceExpression(methodInvocationExpression.TypeInference.TargetType);
1193  return methodInvocationExpression;
1194  }
1195 
1196  if (methodName == "mul")
1197  {
1198  //// Swap all binary expressions in order for matrix multiplications to be compatible with matrix layout
1199  var leftParameter = ConvertToSafeExpressionForBinary(methodInvocationExpression.Arguments[NoSwapForBinaryMatrixOperation ? 0 : 1]);
1200  var rightParameter = ConvertToSafeExpressionForBinary(methodInvocationExpression.Arguments[NoSwapForBinaryMatrixOperation ? 1 : 0]);
1201  return new ParenthesizedExpression(new BinaryExpression(BinaryOperator.Multiply, leftParameter, rightParameter));
1202  }
1203 
1204  if (methodName == "lit")
1205  {
1206  // http://msdn.microsoft.com/en-us/library/bb509619%28v=vs.85%29.aspx
1207  // ret lit(n_dot_l, n_dot_h, m) {
1208  // ambient = 1.
1209  // diffuse = ((n • l) < 0) ? 0 : n • l.
1210  // specular = ((n • l) < 0) || ((n • h) < 0) ? 0 : ((n • h) ^ m).
1211  // return float4((ambient, diffuse, specular, 1);
1212  // }
1214  methodLit.Arguments.Add(new LiteralExpression(1.0f));
1215 
1216  var diffuseArg = new ConditionalExpression(
1217  new BinaryExpression(BinaryOperator.Less, methodInvocationExpression.Arguments[0], new LiteralExpression(0.0f)),
1218  new LiteralExpression(0.0f),
1219  methodInvocationExpression.Arguments[0]);
1220 
1221  methodLit.Arguments.Add(diffuseArg);
1222 
1223  var specularArg =
1225  new BinaryExpression(
1226  BinaryOperator.LogicalOr,
1227  new BinaryExpression(BinaryOperator.Less, methodInvocationExpression.Arguments[0], new LiteralExpression(0.0f)),
1228  new BinaryExpression(BinaryOperator.Less, methodInvocationExpression.Arguments[1], new LiteralExpression(0.0f))),
1229  new LiteralExpression(0.0f),
1230  new MethodInvocationExpression("pow", methodInvocationExpression.Arguments[1], methodInvocationExpression.Arguments[2]));
1231 
1232  methodLit.Arguments.Add(specularArg);
1233  methodLit.Arguments.Add(new LiteralExpression(1.0f));
1234 
1235  //// Swap all binary expressions in order for matrix multiplications to be compatible with matrix layout
1236  return methodLit;
1237  }
1238 
1239  if (methodName == "isfinite")
1240  {
1241  methodVar.Name = "isinf";
1242  var result = new MethodInvocationExpression("not", methodInvocationExpression);
1243  return result;
1244  }
1245 
1246  if (methodName == "log10")
1247  {
1248  methodVar.Name = "log";
1249  var log10 = new MethodInvocationExpression("log", new LiteralExpression(10.0f));
1250  return new BinaryExpression(BinaryOperator.Multiply, methodInvocationExpression, log10);
1251  }
1252 
1253  if (methodName == "saturate")
1254  {
1255  methodVar.Name = "saturate";
1256  methodInvocationExpression.Arguments.Add(new LiteralExpression(0.0f));
1257  methodInvocationExpression.Arguments.Add(new LiteralExpression(1.0f));
1258  }
1259 
1260  // Transform all(x) into all(x != 0) because OpenGL expects only boolean
1261  if (methodName == "all" || methodName == "any")
1262  {
1263  var argType = methodInvocationExpression.Arguments[0].TypeInference.TargetType;
1264  if (argType == null || TypeBase.GetBaseType(argType) != ScalarType.Bool)
1265  {
1266  var castToZero = new MethodInvocationExpression(new TypeReferenceExpression(argType), new LiteralExpression(0));
1267  var notEqual = new MethodInvocationExpression("notEqual", methodInvocationExpression.Arguments[0], castToZero);
1268  methodInvocationExpression.Arguments[0] = notEqual;
1269  }
1270  }
1271 
1272  if (string.Compare(methodName, "D3DCOLORtoUBYTE4", StringComparison.OrdinalIgnoreCase) == 0)
1273  {
1274  return new MethodInvocationExpression(new TypeReferenceExpression(VectorType.Int4), methodInvocationExpression.Arguments[0]) { TypeInference = { TargetType = VectorType.Int4 }};
1275  }
1276 
1277  string methodNameGl;
1278  if (functionMapping.TryGetValue(methodName, out methodNameGl))
1279  methodVar.Name = methodNameGl;
1280  }
1281 
1282  // Convert member expression
1283  var memberReferenceExpression = methodInvocationExpression.Target as MemberReferenceExpression;
1284  if (memberReferenceExpression != null)
1285  {
1286  var targetVariable = FindGlobalVariableFromExpression(memberReferenceExpression.Target);
1287  if (targetVariable == null)
1288  {
1289  parserResult.Error("Unable to find target variable for expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1290  return methodInvocationExpression;
1291  }
1292  var targetVariableType = targetVariable.Type.ResolveType();
1293  if (targetVariableType.IsBuiltIn && targetVariableType.Name.Text.StartsWith("Buffer"))
1294  {
1295  parserResult.Error("Unable to convert Buffer<> variable access [{0}]. Features not supported in GLSL", methodInvocationExpression.Span, methodInvocationExpression);
1296  return methodInvocationExpression;
1297  }
1298  methodDeclaration = memberReferenceExpression.TypeInference.Declaration as MethodDeclaration;
1299 
1300  switch (memberReferenceExpression.Member)
1301  {
1302  // Geometry shader
1303  case "RestartStrip":
1304  methodInvocationExpression.Target = new VariableReferenceExpression("EndPrimitive");
1305  break;
1306 
1307  // Texture object
1308  case "GetDimensions":
1309  // We should not be here
1310  parserResult.Error("GetDimensions should have been already preprocessed for expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1311  break;
1312  case "Load":
1313  case "Sample":
1314  case "SampleBias":
1315  case "SampleGrad":
1316  case "SampleLevel":
1317  {
1318  string methodName = "texture";
1319 
1320  bool isLoad = memberReferenceExpression.Member == "Load";
1321  int baseParameterCount = isLoad ? 1 : 2;
1322 
1323  Variable sampler = null;
1324 
1325  // texture.Load() doesn't require a sampler
1326  if (!isLoad)
1327  {
1328  sampler = this.FindGlobalVariableFromExpression(methodInvocationExpression.Arguments[0]);
1329  }
1330  var glslSampler = GetGLSampler(sampler, targetVariable, true);
1331 
1332  if (TextureFunctionsCompatibilityProfile)
1333  {
1334  if (targetVariable.Type == TextureType.Texture1D)
1335  methodName += "1D";
1336  else if (targetVariable.Type == TextureType.Texture2D)
1337  methodName += "2D";
1338  else if (targetVariable.Type == TextureType.Texture3D)
1339  methodName += "3D";
1340  else if (targetVariable.Type == TextureType.TextureCube)
1341  methodName += "Cube";
1342  else
1343  parserResult.Error("Unable to find texture profile in compatibility mode [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1344  }
1345 
1346  if (glslSampler == null)
1347  {
1348  parserResult.Error("Unable to find matching texture/sampler expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1349  return methodInvocationExpression;
1350  }
1351 
1352  bool hasBias = memberReferenceExpression.Member == "SampleBias";
1353  if (hasBias)
1354  baseParameterCount++;
1355 
1356  if (memberReferenceExpression.Member == "SampleGrad")
1357  {
1358  baseParameterCount += 2;
1359  methodName += "Grad";
1360  }
1361 
1362  if (memberReferenceExpression.Member == "SampleLevel")
1363  {
1364  baseParameterCount++;
1365  methodName += "Lod";
1366  }
1367 
1368  if (isLoad)
1369  {
1370  methodName += "Lod";
1371  }
1372 
1373  if (methodInvocationExpression.Arguments.Count == baseParameterCount + 1)
1374  {
1375  methodName += "Offset";
1376  }
1377  else if (methodInvocationExpression.Arguments.Count != baseParameterCount)
1378  {
1379  parserResult.Error("Unable to match arguments count with expected parameters for expression [{0}]", methodInvocationExpression.Span, methodInvocationExpression);
1380  return methodInvocationExpression;
1381  }
1382 
1383  var samplerParameter = new VariableReferenceExpression(glslSampler.Name);
1384 
1385  // texture.Sample has a sampler parameter but texture.Load doesn't, so replace/add accordingly
1386  if (isLoad)
1387  methodInvocationExpression.Arguments.Insert(0, samplerParameter);
1388  else
1389  methodInvocationExpression.Arguments[0] = samplerParameter;
1390 
1391  // SampleBias and textureOffset conversion requires a parameter swap between bias and offset.
1392  if (hasBias && methodName == "textureOffset")
1393  {
1394  var temp = methodInvocationExpression.Arguments[2];
1395  methodInvocationExpression.Arguments[3] = methodInvocationExpression.Arguments[2];
1396  methodInvocationExpression.Arguments[2] = temp;
1397  }
1398 
1399  if (isLoad)
1400  {
1401  // Since Texture.Load works with integer coordinates, need to convert
1402  // texture.Load(coords, [offset]) to textureLod[Offset](texture_sampler, coords.xy / textureSize(texture_sampler), coords.z, [offset])
1403 
1404  string dimP = "??";
1405  string mipLevel = "?";
1406 
1407  switch (targetVariableType.Name.Text)
1408  {
1409  case "Texture1D":
1410  dimP = "x";
1411  mipLevel = "y";
1412  break;
1413  case "Texture2D":
1414  case "Texture2DMS":
1415  case "Texture1DArray":
1416  dimP = "xy";
1417  mipLevel = "z";
1418  break;
1419  case "Texture2DArray":
1420  case "Texture2DArrayDMS":
1421  dimP = "xyz";
1422  mipLevel = "w";
1423  break;
1424  }
1425 
1426  methodInvocationExpression.Arguments.Insert(2, NewCast(ScalarType.Float, new MemberReferenceExpression(methodInvocationExpression.Arguments[1].DeepClone(), mipLevel)));
1427  methodInvocationExpression.Arguments[1] = NewCast(new VectorType(ScalarType.Float, dimP.Length), new BinaryExpression(
1428  BinaryOperator.Divide,
1429  new MemberReferenceExpression(methodInvocationExpression.Arguments[1], dimP),
1430  NewCast(new VectorType(ScalarType.Float, dimP.Length), new MethodInvocationExpression("textureSize", new VariableReferenceExpression(glslSampler.Name), new LiteralExpression(0)))));
1431  }
1432 
1433  methodInvocationExpression.Target = new VariableReferenceExpression(methodName);
1434 
1435  // TODO: Check how many components are required
1436  // methodInvocationExpression.Arguments[1] = new MemberReferenceExpression(new ParenthesizedExpression(methodInvocationExpression.Arguments[1]), "xy");
1437  }
1438 
1439  break;
1440  }
1441  }
1442 
1443  // Handle type reference expression
1444  var typeReferenceExpression = methodInvocationExpression.Target as TypeReferenceExpression;
1445  if (typeReferenceExpression != null)
1446  {
1447  // Convert matrix type initializers
1448  var matrixType = typeReferenceExpression.Type.ResolveType() as MatrixType;
1449  if (matrixType != null)
1450  {
1451  methodInvocationExpression.Arguments = this.ConvertMatrixInitializer(matrixType, methodInvocationExpression.Arguments);
1452  }
1453  }
1454 
1455  // Add default parameters
1456  if (methodDeclaration != null)
1457  {
1458  for (int i = methodInvocationExpression.Arguments.Count; i < methodDeclaration.Parameters.Count; i++)
1459  methodInvocationExpression.Arguments.Add(methodDeclaration.Parameters[i].InitialValue);
1460  }
1461 
1462  CheckCastMethod(methodInvocationExpression);
1463 
1464  // For GeometryShader remove stream type method invocation
1465  RemoveStreamTypeFromMethodInvocation(methodInvocationExpression);
1466 
1467  return methodInvocationExpression;
1468  }
1469 
1470  private void RemoveStreamTypeFromMethodInvocation(MethodInvocationExpression expression)
1471  {
1472  // Remove parameters that are StreamType
1473  for (int i = expression.Arguments.Count - 1; i >= 0; i--)
1474  {
1475  var argument = expression.Arguments[i];
1476  if (ClassType.IsStreamType(argument.TypeInference.TargetType))
1477  {
1478  expression.Arguments.RemoveAt(i);
1479  }
1480  }
1481  }
1482 
1483  private void RemoveStreamTypeFromMethodDefinition(MethodDeclaration declaration)
1484  {
1485  // Remove parameters that are StreamType
1486  for (int i = declaration.Parameters.Count - 1; i >= 0; i--)
1487  {
1488  var argument = declaration.Parameters[i];
1489  if (ClassType.IsStreamType(argument.Type.TypeInference.TargetType))
1490  {
1491  declaration.Parameters.RemoveAt(i);
1492  }
1493  }
1494  }
1495 
1496  /// <summary>
1497  /// Visits the specified conditional expression.
1498  /// </summary>
1499  /// <param name="conditionalExpression">The conditional expression.</param>
1500  [Visit]
1501  protected Expression Visit(ConditionalExpression conditionalExpression)
1502  {
1503  Visit((Node)conditionalExpression);
1504 
1505  var conditionType = conditionalExpression.Condition.TypeInference.TargetType;
1506 
1507  // Convert float4(xxx) ? left : right to mix(left, right, float4(xxx) == 0);
1508  if (conditionType is VectorType)
1509  {
1510  var methodInvocation = new MethodInvocationExpression("mix", conditionalExpression.Left, conditionalExpression.Right,
1511  new MethodInvocationExpression("equal", conditionalExpression.Condition, new MethodInvocationExpression(new TypeReferenceExpression(conditionType), new LiteralExpression(0)) ));
1512  return methodInvocation;
1513  }
1514  else
1515  {
1516  conditionalExpression.Condition = ConvertCondition(conditionalExpression.Condition);
1517  }
1518 
1519  return conditionalExpression;
1520  }
1521 
1522  /// <summary>
1523  /// Visits the specified constant buffer.
1524  /// </summary>
1525  /// <param name="constantBuffer">The constant buffer.</param>
1526  [Visit]
1527  protected void Visit(ConstantBuffer constantBuffer)
1528  {
1529  Visit((Node)constantBuffer);
1530 
1531  // Remove initializers from constant buffers
1532  foreach (var variable in constantBuffer.Members.OfType<Variable>())
1533  {
1534  if (variable.InitialValue != null)
1535  {
1536  parserResult.Warning("Initializer in uniform block are not supported in glsl [{0}]", variable.Span, variable);
1537  variable.InitialValue = null;
1538  }
1539  }
1540  }
1541 
1542  /// <summary>
1543  /// Visits the specified var ref expr.
1544  /// </summary>
1545  /// <param name="varRefExpr">The var ref expr.</param>
1546  /// <returns>A transformed expression.</returns>
1547  [Visit]
1549  {
1550  Visit((Node)varRefExpr);
1551 
1552  // If this is a global variable used as a temporary, don't perform any transform on it
1553  if (globalUniformVisitor.IsVariableAsGlobalTemporary(varRefExpr))
1554  {
1555  return varRefExpr;
1556  }
1557 
1558  // Use ConvertExpression on variable.
1559  var variable = FindDeclaration(varRefExpr.Name) as Variable;
1560  if (variable != null)
1561  {
1562  var result = this.ConvertReferenceToSemantics(varRefExpr, variable.Semantic(), variable.Type.ResolveType(), variable.Name, variable.Span);
1563  if (result != null)
1564  return result;
1565  }
1566 
1567  return varRefExpr;
1568  }
1569 
1570  /// <summary>
1571  /// Visits the specified if statement.
1572  /// </summary>
1573  /// <param name="ifStatement">If statement.</param>
1574  [Visit]
1575  protected void Visit(IfStatement ifStatement)
1576  {
1577  Visit((Node)ifStatement);
1578  ifStatement.Condition = ConvertCondition(ifStatement.Condition);
1579  }
1580 
1581  /// <summary>
1582  /// Visit the for statement and unroll it if necessary
1583  /// </summary>
1584  /// <param name="forStatement"></param>
1585  /// <returns></returns>
1586  [Visit]
1587  protected Node Visit(ForStatement forStatement)
1588  {
1589  Visit((Node)forStatement);
1590 
1591  // unroll foreach if necessary
1592  if (UnrollForLoops && forStatement.Attributes.OfType<AttributeDeclaration>().Any(x => x.Name.Text == "unroll"))
1593  {
1594  var breakFlag = new Variable(ScalarType.Bool, "isBreak" + breakIndex, new LiteralExpression(false));
1595  ++breakIndex;
1596  var breakVisitor = new BreakContinueVisitor();
1597  var hasBreak = breakVisitor.Run(forStatement, breakFlag, "break", parserResult);
1598 
1599  var continueFlag = new Variable(ScalarType.Bool, "isContinue" + breakIndex, new LiteralExpression(false));
1600  ++breakIndex;
1601  var continueVisitor = new BreakContinueVisitor();
1602  var hasContinue = continueVisitor.Run(forStatement, continueFlag, "continue", parserResult);
1603 
1604  int startValue;
1605  var varName = GetStartForStatement(forStatement, out startValue);
1606 
1607  if (varName != null)
1608  {
1609  var iterCount = GetIterCountForStatement(forStatement, varName, startValue);
1610 
1611  if (iterCount > 0)
1612  {
1613  var statements = new BlockStatement(new StatementList());
1614  statements.Statements.Add(forStatement.Start);
1615  if (hasBreak)
1616  statements.Statements.Add(new DeclarationStatement(breakFlag));
1617  if (hasContinue)
1618  statements.Statements.Add(new DeclarationStatement(continueFlag));
1619 
1620  var lastStatement = statements;
1621 
1622  for (int i = 0; i < iterCount; ++i)
1623  {
1624  var clonedBody = forStatement.Body.DeepClone();
1625  var blockStatement = clonedBody as BlockStatement ?? new BlockStatement(new StatementList(clonedBody));
1626  blockStatement.Statements.Add(new ExpressionStatement(forStatement.Next));
1627 
1628  if (hasContinue) // reset the flag
1629  blockStatement.Statements.Add(new ExpressionStatement(new AssignmentExpression(AssignmentOperator.Default, new VariableReferenceExpression(continueFlag), new LiteralExpression(false))));
1630 
1631  if (hasBreak)
1632  {
1633  var ifStatement = new IfStatement();
1634  ifStatement.Condition = new UnaryExpression(UnaryOperator.LogicalNot, new VariableReferenceExpression(breakFlag));
1635  ifStatement.Then = blockStatement;
1636  lastStatement.Statements.Add(ifStatement);
1637  }
1638  else
1639  {
1640  lastStatement.Statements.Add(blockStatement);
1641  }
1642  lastStatement = blockStatement;
1643  }
1644  return statements;
1645  }
1646  if (iterCount == 0)
1647  {
1648  return new EmptyStatement();
1649  }
1650  }
1651  parserResult.Error("Unable to unroll for statement [{0}]", forStatement.Span, forStatement);
1652  }
1653 
1654  return forStatement;
1655  }
1656 
1657  /// <summary>
1658  /// Get the Variable used
1659  /// </summary>
1660  /// <param name="forStatement">the for statement</param>
1661  /// <param name="startValue">the start value of the loop, to fill</param>
1662  /// <returns>the variable</returns>
1663  private static string GetStartForStatement(ForStatement forStatement, out int startValue)
1664  {
1665  var startStatement = forStatement.Start as DeclarationStatement;
1666  var startStatementAssign = forStatement.Start as ExpressionStatement;
1667  startValue = 0;
1668 
1669  if (startStatement != null)
1670  {
1671  var variable = startStatement.Content as Variable;
1672  if (variable != null)
1673  {
1674  var evaluatorStart = new ExpressionEvaluator();
1675  var resultStart = evaluatorStart.Evaluate(variable.InitialValue);
1676  if (resultStart.HasErrors)
1677  return null;
1678  startValue = (int)((double)resultStart.Value);
1679 
1680  return variable.Name.Text;
1681  }
1682  }
1683  else if (startStatementAssign != null)
1684  {
1685  var assign = startStatementAssign.Expression as AssignmentExpression;
1686  if (assign != null && assign.Operator == AssignmentOperator.Default)
1687  {
1688  var vre = assign.Target as VariableReferenceExpression;
1689  if (vre != null)
1690  {
1691  var evaluatorStart = new ExpressionEvaluator();
1692  var resultStart = evaluatorStart.Evaluate(assign.Value);
1693  if (resultStart.HasErrors)
1694  return null;
1695  startValue = (int)((double)resultStart.Value);
1696 
1697  return vre.Name.Text;
1698  }
1699  }
1700  }
1701 
1702  return null;
1703  }
1704 
1705  /// <summary>
1706  /// Get the number of loops
1707  /// </summary>
1708  /// <param name="forStatement">the for statement</param>
1709  /// <param name="variableName">the name of the iterator variable</param>
1710  /// <param name="startValue">the start value of the iterator</param>
1711  /// <returns>the number of loops</returns>
1712  private static int GetIterCountForStatement(ForStatement forStatement, string variableName, int startValue)
1713  {
1714  var condition = forStatement.Condition as BinaryExpression;
1715  if (condition == null)
1716  return -1;
1717 
1718  var evaluatorStop = new ExpressionEvaluator();
1719  var resultStop = evaluatorStop.Evaluate(condition.Right);
1720  if (resultStop.HasErrors)
1721  return -1;
1722 
1723  var stopValue = (int)((double)resultStop.Value);
1724  var step = 1;
1725 
1726  var stepExpr = forStatement.Next as UnaryExpression;
1727  if (stepExpr == null)
1728  {
1729  var stepAssign = forStatement.Next as AssignmentExpression;
1730  if (stepAssign != null)
1731  {
1732  if (stepAssign.Operator == AssignmentOperator.Default)
1733  {
1734  var assignedVar = stepAssign.Target as VariableReferenceExpression;
1735  var valueAssigned = stepAssign.Value as BinaryExpression;
1736  if (assignedVar == null || valueAssigned == null)
1737  return -1;
1738 
1739  var left = valueAssigned.Left as VariableReferenceExpression;
1740  var right = valueAssigned.Right as VariableReferenceExpression;
1741 
1742  if (left != null && left.Name.Text == variableName && valueAssigned.Right is LiteralExpression)
1743  {
1744  step = (int)(valueAssigned.Right as LiteralExpression).Value;
1745  }
1746  else if (right != null && right.Name.Text == variableName && valueAssigned.Left is LiteralExpression)
1747  {
1748  step = (int)(valueAssigned.Left as LiteralExpression).Value;
1749  }
1750  else
1751  return -1;
1752  }
1753  else if (stepAssign.Operator == AssignmentOperator.Addition || stepAssign.Operator == AssignmentOperator.Subtraction)
1754  {
1755  var assignedVar = stepAssign.Target as VariableReferenceExpression;
1756  if (assignedVar == null || assignedVar.Name.Text != variableName)
1757  return -1;
1758 
1759  var evaluatorValueAssigned = new ExpressionEvaluator();
1760  var resultValueAssigned = evaluatorValueAssigned.Evaluate(stepAssign.Value);
1761  if (resultValueAssigned.HasErrors)
1762  return -1;
1763 
1764  step = (int)((double)resultValueAssigned.Value);
1765  if (stepAssign.Operator == AssignmentOperator.Subtraction)
1766  step = -step;
1767  }
1768  }
1769  else
1770  return -1;
1771  }
1772  else
1773  {
1774  switch (stepExpr.Operator)
1775  {
1776  case UnaryOperator.PostDecrement:
1777  case UnaryOperator.PreDecrement:
1778  step = -1;
1779  break;
1780  case UnaryOperator.PostIncrement:
1781  case UnaryOperator.PreIncrement:
1782  step = 1;
1783  break;
1784  }
1785  }
1786 
1787  switch (condition.Operator)
1788  {
1789  case BinaryOperator.Less:
1790  return (stopValue - startValue - 1) / step + 1;
1791  case BinaryOperator.Greater:
1792  return (stopValue - startValue - 1) / step + 1;
1793  case BinaryOperator.LessEqual:
1794  return (stopValue - startValue) / step + 1;
1795  case BinaryOperator.GreaterEqual:
1796  return (stopValue - startValue) / step + 1;
1797  case BinaryOperator.Equality:
1798  {
1799  if (startValue == stopValue)
1800  return 1;
1801  else
1802  return 0;
1803  }
1804  default:
1805  return -1;
1806  }
1807  }
1808 
1809  /// <summary>
1810  /// Visits the specified expression.
1811  /// </summary>
1812  /// <param name="expression">The expression.</param>
1813  /// <returns>A transformed expression</returns>
1814  [Visit]
1816  {
1817  Visit((Node)expression);
1818 
1819  // A matrix contains values organized in rows and columns, which can be accessed using the structure operator "." followed by one of two naming sets:
1820  // The zero-based row-column position:
1821  // _m00, _m01, _m02, _m03
1822  // _m10, _m11, _m12, _m13
1823  // _m20, _m21, _m22, _m23
1824  // _m30, _m31, _m32, _m33
1825  // The one-based row-column position:
1826  // _11, _12, _13, _14
1827  // _21, _22, _23, _24
1828  // _31, _32, _33, _34
1829  // _41, _42, _43, _44
1830  var matrixType = expression.Target.TypeInference.TargetType as MatrixType;
1831  if (matrixType != null)
1832  {
1833  var swizzles = HlslSemanticAnalysis.MatrixSwizzleDecode(expression);
1834 
1835  if (swizzles.Count == 1)
1836  return new IndexerExpression(new IndexerExpression(expression.Target, new LiteralExpression(swizzles[0].Row)), new LiteralExpression(swizzles[0].Column));
1837 
1838  if (swizzles.Count > 1 && swizzles.Count <= 4)
1839  {
1840  var swizzleVectorInvoke = new MethodInvocationExpression(new TypeReferenceExpression(expression.TypeInference.TargetType));
1841 
1842  foreach (var swizzle in swizzles)
1843  swizzleVectorInvoke.Arguments.Add(new IndexerExpression(new IndexerExpression(expression.Target, new LiteralExpression(swizzle.Row)), new LiteralExpression(swizzle.Column)));
1844  return swizzleVectorInvoke;
1845  }
1846  }
1847 
1848  return expression;
1849  }
1850 
1851  /// <summary>
1852  /// Visits the specified array creation expression.
1853  /// </summary>
1854  /// <param name="arrayCreationExpression">The array creation expression.</param>
1855  /// <returns>A transformed expression</returns>
1856  [Visit]
1857  protected Expression Visit(ArrayInitializerExpression arrayCreationExpression)
1858  {
1859  var variable = ParentNode as Variable;
1860 
1861  var result = (Expression)Visit((Node)arrayCreationExpression);
1862 
1863  // If there is a parent variable and no subscript, It is probably a cast to an implicit array type (float2,float3,float4...etc.)
1864  if (variable != null)
1865  {
1866  var variableType = variable.Type.ResolveType();
1867 
1868  var arrayType = variableType as ArrayType;
1869  if (arrayType != null)
1870  {
1871  return this.ConvertArrayInitializer(arrayType, arrayCreationExpression);
1872  }
1873  else
1874  {
1875  // Transform array creation to an explicit cast
1876  // HLSL => float4 toto = {1,2,3,4};
1877  // GLSL => vec4 toto = vec4(1,2,3,4);
1878  var items = new List<Expression>();
1879  FlattenArrayCreationExpression(arrayCreationExpression, items);
1880  var castToType = new MethodInvocationExpression(new TypeReferenceExpression(variable.Type));
1881 
1882  // If matrix type, then use common function to convert the initializer
1883  var matrixType = variableType as MatrixType;
1884  if (matrixType != null)
1885  {
1886  items = this.ConvertMatrixInitializer(matrixType, items);
1887  }
1888 
1889  foreach (var expression in items)
1890  castToType.Arguments.Add(expression);
1891 
1892  result = castToType;
1893  }
1894  }
1895 
1896  return result;
1897  }
1898 
1899  /// <summary>
1900  /// Visits the specified assign expression.
1901  /// </summary>
1902  /// <param name="assignExpression">The assign expression.</param>
1903  /// <returns>A transformed expression</returns>
1904  [Visit]
1905  protected Expression Visit(AssignmentExpression assignExpression)
1906  {
1907  // Put a special flag while visiting assignment target for tracking assignment to input varying (not allowed in OpenGL)
1908  // TODO: use stack of assignmentTarget instead, as it would not work with nested assignement
1909  isAssignmentTarget = true;
1910  assignExpression.Target = (Expression)VisitDynamic(assignExpression.Target);
1911  isAssignmentTarget = false;
1912  assignExpression.Value = (Expression)VisitDynamic(assignExpression.Value);
1913 
1914  // If right expression is null, we can assume that it was removed on the right side
1915  // So we can safely remove the whole expression
1916  if (assignExpression.Value == null)
1917  return null;
1918 
1919  return assignExpression;
1920  }
1921 
1922  /// <summary>
1923  /// Visits the specified technique.
1924  /// </summary>
1925  /// <param name="technique">The technique.</param>
1926  /// <returns>The technique</returns>
1927  [Visit]
1928  protected Technique Visit(Technique technique)
1929  {
1930  // Skip all techniques while parsing
1931  return technique;
1932  }
1933 
1934  /// <summary>
1935  /// Visits the specified binary expression.
1936  /// </summary>
1937  /// <param name="binaryExpression">The binary expression.</param>
1938  /// <returns>A transformed binary expression.</returns>
1939  [Visit]
1940  protected Expression Visit(BinaryExpression binaryExpression)
1941  {
1942  Visit((Node)binaryExpression);
1943 
1944  // -----------------------------------------------------
1945  // Handle binary expression with gl_FrontFacing variable
1946  // -----------------------------------------------------
1947  bool isLeftFrontFacing = string.Compare(VariableReferenceExpression.GetVariableName(binaryExpression.Left), gl_FrontFacing, StringComparison.OrdinalIgnoreCase) == 0;
1948  bool isRightFrontFacing = string.Compare(VariableReferenceExpression.GetVariableName(binaryExpression.Right), gl_FrontFacing, StringComparison.OrdinalIgnoreCase) == 0;
1949  if (isLeftFrontFacing || isRightFrontFacing)
1950  {
1951  bool isLessOperator = binaryExpression.Operator == BinaryOperator.Less || binaryExpression.Operator == BinaryOperator.LessEqual;
1952  bool isGreaterOperator = binaryExpression.Operator == BinaryOperator.Greater || binaryExpression.Operator == BinaryOperator.GreaterEqual;
1953 
1954  // If the operator is supported, then return gl_FrontFacing or !glFrontFacing
1955  var glFrontFacingVar = isLeftFrontFacing ? binaryExpression.Left : binaryExpression.Right;
1956  glFrontFacingVar.TypeInference.TargetType = ScalarType.Bool;
1957  if (isLessOperator || isGreaterOperator)
1958  {
1959  if ((isLessOperator && isLeftFrontFacing) || (isRightFrontFacing && isGreaterOperator))
1960  return new UnaryExpression(UnaryOperator.LogicalNot, glFrontFacingVar) { TypeInference = { TargetType = ScalarType.Bool } };
1961 
1962  return glFrontFacingVar;
1963  }
1964 
1965  // Else convert the glFrontFacing to a -1/1 variable
1966  var newGlFrontFacing = new ParenthesizedExpression(new ConditionalExpression(glFrontFacingVar, new LiteralExpression(1), new LiteralExpression(-1)));
1967 
1968  if (isLeftFrontFacing)
1969  binaryExpression.Left = newGlFrontFacing;
1970  else
1971  binaryExpression.Right = newGlFrontFacing;
1972  }
1973 
1974  // -----------------------------------------------------
1975  // Handle conversion between types
1976  // -----------------------------------------------------
1977  var leftType = binaryExpression.Left.TypeInference.TargetType;
1978  var rightType = binaryExpression.Right.TypeInference.TargetType;
1979 
1980  Expression outputExpression = binaryExpression;
1981 
1982  if (leftType != null && rightType != null)
1983  {
1984  bool isOperationOnVectors = leftType is VectorType && rightType is VectorType && ((VectorType)leftType).Dimension > 1 && ((VectorType)rightType).Dimension > 1;
1985 
1986  if (binaryExpression.Operator == BinaryOperator.Multiply)
1987  {
1988  if (leftType is MatrixType && rightType is MatrixType)
1989  {
1990  var matrixMul = new MethodInvocationExpression(new VariableReferenceExpression(new Identifier("matrixCompMult")));
1991  matrixMul.Arguments.Add(binaryExpression.Left);
1992  matrixMul.Arguments.Add(binaryExpression.Right);
1993 
1994  outputExpression = matrixMul;
1995  }
1996  }
1997  else if (binaryExpression.Operator == BinaryOperator.Modulo)
1998  {
1999  if (!ScalarType.IsInteger(leftType) || !ScalarType.IsInteger(rightType))
2000  {
2001  var matrixMul = new MethodInvocationExpression(new VariableReferenceExpression(new Identifier("mod")));
2002  matrixMul.Arguments.Add(binaryExpression.Left);
2003  matrixMul.Arguments.Add(binaryExpression.Right);
2004 
2005  outputExpression = matrixMul;
2006  }
2007  }
2008  else if (binaryExpression.Operator == BinaryOperator.Less || binaryExpression.Operator == BinaryOperator.Greater || binaryExpression.Operator == BinaryOperator.LessEqual
2009  || binaryExpression.Operator == BinaryOperator.GreaterEqual || binaryExpression.Operator == BinaryOperator.Equality || binaryExpression.Operator == BinaryOperator.Inequality)
2010  {
2011  if (isOperationOnVectors)
2012  {
2013  string comparisonName;
2014  switch (binaryExpression.Operator)
2015  {
2016  case BinaryOperator.Less:
2017  comparisonName = "lessThan";
2018  break;
2019  case BinaryOperator.LessEqual:
2020  comparisonName = "lessThanEqual";
2021  break;
2022  case BinaryOperator.Greater:
2023  comparisonName = "greaterThan";
2024  break;
2025  case BinaryOperator.GreaterEqual:
2026  comparisonName = "greaterThanEqual";
2027  break;
2028  case BinaryOperator.Equality:
2029  comparisonName = "equal";
2030  break;
2031  case BinaryOperator.Inequality:
2032  comparisonName = "notEqual";
2033  break;
2034  default:
2035  parserResult.Error("Unsupported binary expression on vectors [{0}]", binaryExpression.Span, binaryExpression);
2036  return binaryExpression;
2037  }
2038 
2039  var comparisonExpr = new MethodInvocationExpression(new VariableReferenceExpression(new Identifier(comparisonName)));
2040  comparisonExpr.Arguments.Add(binaryExpression.Left);
2041  comparisonExpr.Arguments.Add(binaryExpression.Right);
2042 
2043  int dimension = ((VectorType)binaryExpression.TypeInference.TargetType).Dimension;
2044  comparisonExpr.TypeInference.TargetType = new VectorType(ScalarType.Bool, dimension);
2045  outputExpression = comparisonExpr;
2046  }
2047  }
2048  else if (binaryExpression.Operator == BinaryOperator.LogicalOr || binaryExpression.Operator == BinaryOperator.LogicalAnd)
2049  {
2050  binaryExpression.Left = ConvertCondition(binaryExpression.Left);
2051  binaryExpression.Right = ConvertCondition(binaryExpression.Right);
2052  binaryExpression.TypeInference.TargetType = ScalarType.Bool;
2053 
2054  if (isOperationOnVectors)
2055  {
2056  parserResult.Error(
2057  "Boolean operation && || on expression [{0}] cannot be converted safely to GLSL, as GLSL doesn't support boolean operators function on a per-component basis. Code is generated but invalid",
2058  binaryExpression.Span,
2059  binaryExpression);
2060  }
2061  }
2062  }
2063 
2064  return outputExpression;
2065  }
2066 
2067  /// <summary>
2068  /// Visits the specified return statement.
2069  /// </summary>
2070  /// <param name="returnStatement">The return statement.</param>
2071  /// <returns>A transformed return statement.</returns>
2072  [Visit]
2073  protected Statement Visit(ReturnStatement returnStatement)
2074  {
2075  Visit((Node)returnStatement);
2076 
2077  // Only transform return in entry function
2078  if (!IsInEntryPoint)
2079  return returnStatement;
2080 
2081  // This should only process return statements with ConvertReturn which are not detected at the block level.
2082  // As an example, a return statement which is not enclosed in a block, such as "if (X) return Y;", should be converted to if(X) { out_x = x; out_y = y; ... }
2083  return ConvertReturn(returnStatement.Value, true, returnStatement.Span);
2084  }
2085 
2086  /// <summary>
2087  /// Visits the specified statement list.
2088  /// </summary>
2089  /// <param name="statementList">The statement list.</param>
2090  /// <returns>
2091  /// A transformed statement list.
2092  /// </returns>
2093  [Visit]
2094  protected Statement Visit(StatementList statementList)
2095  {
2096  // Try to transform return statement with ConvertReturn at the block level first.
2097  // As an example, { stmt1; return Y; } gets converted to { stmt1; out_x = x; out_y = y; ... }
2098  var newStatementList = new StatementList();
2099  for (int i = 0; i < statementList.Statements.Count; i++)
2100  {
2101  var stmt = statementList.Statements[i];
2102  bool converted = false;
2103 
2104  if (stmt is ReturnStatement)
2105  {
2106  // Only transform return in entry function
2107  if (IsInEntryPoint)
2108  {
2109  var returnValue = ((ReturnStatement)stmt).Value;
2110 
2111  // Don't emit return for last return of a function
2112  bool emitReturn = !(ParentNode is MethodDefinition && (i + 1) == statementList.Statements.Count);
2113 
2114  // Return statements could not have a value
2115  if (returnValue != null)
2116  {
2117  var subStatements = ConvertReturn(((ReturnStatement)stmt).Value, emitReturn, stmt.Span);
2118  if (subStatements is StatementList)
2119  newStatementList.AddRange((StatementList)subStatements);
2120  else
2121  newStatementList.Add(subStatements);
2122 
2123  converted = true;
2124  }
2125  else if (!emitReturn)
2126  converted = true;
2127  }
2128  }
2129  else if (stmt is DeclarationStatement)
2130  {
2131  var variable = ((DeclarationStatement)stmt).Content as Variable;
2132 
2133  // Remove register/semantics from local variable declaration
2134  if (variable != null)
2135  variable.Qualifiers.Values.RemoveAll(qualifierArg => qualifierArg is RegisterLocation || qualifierArg is Semantic);
2136  }
2137  else if (stmt is ExpressionStatement)
2138  {
2139  var exprStmt = (ExpressionStatement)stmt;
2140 
2141  // Handle tuple cast. Only support default scalars
2142  if (exprStmt.Expression is AssignmentExpression)
2143  {
2144  var assignExpression = exprStmt.Expression as AssignmentExpression;
2145  if (assignExpression.Target is MethodInvocationExpression && assignExpression.Operator == AssignmentOperator.Default)
2146  {
2147  var tupleExpression = (MethodInvocationExpression)assignExpression.Target;
2148  var typeReferenceExpression = tupleExpression.Target as TypeReferenceExpression;
2149  var tupleType = typeReferenceExpression != null ? typeReferenceExpression.Type.ResolveType() : null;
2150 
2151  if (typeReferenceExpression != null && tupleType != null && !(tupleType is MatrixType))
2152  {
2153  var tupleBlock = new BlockStatement();
2154  const string TemporaryTupleName = "_tuple_temp_";
2155  var variableTuple = new Variable(VectorType.Float4, TemporaryTupleName, assignExpression.Target);
2156  tupleBlock.Statements.Add(new DeclarationStatement(variableTuple));
2157 
2158  int startMember = 0;
2159 
2160  const string SwizzleMembers = "xyzw";
2161 
2162  bool hasError = false;
2163 
2164  foreach (var expression in tupleExpression.Arguments)
2165  {
2166  var argumentType = expression.TypeInference.TargetType;
2167  if (argumentType != null)
2168  {
2169  var argumentDimension = (argumentType is VectorType) ? ((VectorType)argumentType).Dimension : 1;
2170 
2171  tupleBlock.Statements.Add(
2172  new ExpressionStatement(
2173  new AssignmentExpression(
2174  AssignmentOperator.Default,
2175  expression,
2176  new MemberReferenceExpression(new VariableReferenceExpression(TemporaryTupleName), SwizzleMembers.Substring(startMember, argumentDimension)))));
2177  startMember += argumentDimension;
2178  }
2179  else
2180  hasError = true;
2181  }
2182 
2183  if (!hasError)
2184  {
2185  converted = true;
2186  newStatementList.Add(tupleBlock);
2187  }
2188  }
2189  }
2190  }
2191  else
2192  {
2193  var methodInvocationExpr = exprStmt.Expression as MethodInvocationExpression;
2194  var method = methodInvocationExpr != null ? methodInvocationExpr.Target as MemberReferenceExpression : null;
2195 
2196  // Handle geometry shader vertex emit
2197  if (method != null && method.Target is VariableReferenceExpression)
2198  {
2199  var targetVariable = (VariableReferenceExpression) method.Target;
2200  var targetType = targetVariable.TypeInference.TargetType;
2201  if (ClassType.IsStreamType(targetType))
2202  {
2203  if (method.Member == "Append")
2204  {
2205  //var globalVariable = shader.Declarations.Find(node => node is Variable && ((Variable) node).Name == targetVariable.Name);
2206  //if (globalVariable == null)
2207  //{
2208  // var streamType = ((ClassType) targetType).GenericArguments[0];
2209  // var streamOutVariable = new Variable(new ArrayType(streamType), targetVariable.Name);
2210  // streamOutVariable.Qualifiers |= ParameterQualifier.Out;
2211  // AddGlobalDeclaration(streamOutVariable);
2212  //}
2213 
2214  if (targetType.Name == "TriangleStream")
2215  geometryLayoutOutput = "triangle_strip";
2216  else if (targetType.Name == "LineStream")
2217  geometryLayoutOutput = "line_strip";
2218  else if (targetType.Name == "PointStream")
2219  geometryLayoutOutput = "points";
2220  else
2221  {
2222  parserResult.Error("Unknown OutputStream type [{0}] (should be TriangleStream, LineStream or PointStream", exprStmt.Span, targetType.Name);
2223  return newStatementList;
2224  }
2225 
2226  var returnStatement = ConvertReturn(methodInvocationExpr.Arguments[0], false, null);
2227  if (returnStatement is StatementList)
2228  newStatementList.AddRange((StatementList) returnStatement);
2229  else
2230  newStatementList.Add(returnStatement);
2231  newStatementList.Add(new ExpressionStatement(new MethodInvocationExpression(new VariableReferenceExpression("EmitVertex"))));
2232  converted = true;
2233  }
2234  else if (method.Member == "RestartStrip")
2235  {
2236  newStatementList.Add(new ExpressionStatement(new MethodInvocationExpression(new VariableReferenceExpression("EndPrimitive"))));
2237  converted = true;
2238  }
2239  }
2240  }
2241  }
2242  }
2243 
2244  if (!converted)
2245  newStatementList.Add(stmt);
2246  }
2247 
2248  Visit((Node)newStatementList);
2249 
2250  return newStatementList;
2251  }
2252 
2253  /// <summary>
2254  /// Visits the specified indexer expression.
2255  /// </summary>
2256  /// <param name="indexerExpression">The indexer expression.</param>
2257  /// <returns>A transformed indexer expression</returns>
2258  [Visit]
2259  protected Expression Visit(IndexerExpression indexerExpression)
2260  {
2261  // Collect all indices in the order of the declaration
2262  var targetIterator = indexerExpression.Target;
2263  var indices = new List<Expression> { indexerExpression.Index };
2264  while (targetIterator is IndexerExpression)
2265  {
2266  indices.Add(((IndexerExpression)targetIterator).Index);
2267  targetIterator = ((IndexerExpression)targetIterator).Target;
2268  }
2269 
2270  // Check that index apply to an array variable
2271  var variableReferenceExpression = targetIterator as VariableReferenceExpression;
2272  MatrixType matrixType = null;
2273  if (variableReferenceExpression != null)
2274  {
2275  var variable = FindDeclaration(variableReferenceExpression.Name) as Variable;
2276 
2277  // If array is a multidimension array
2278  var variableType = variable != null ? variable.Type.ResolveType() : null;
2279  var arrayType = variableType as ArrayType;
2280  matrixType = variableType as MatrixType;
2281 
2282  if (arrayType != null && arrayType.Dimensions.Count == indices.Count)
2283  {
2284  if (!this.listOfMultidimensionArrayVariable.Contains(variable))
2285  this.listOfMultidimensionArrayVariable.Add(variable);
2286 
2287  // Transform multi-dimensionnal array to single dimension
2288  // float myarray[s1][s2][s3]...[sn] = {{.{..{...}}};
2289  // float value = myarray[i1][i2][i3]...[in] => float value = myarray[(i1)*(s2)*(s3)*...*(sn) + (i2)*(s3)*...*(sn) + (i#)*(s#+1)*(s#+2)*...*(sn)];
2290  Expression finalIndex = null;
2291  for (int i = 0; i < indices.Count; i++)
2292  {
2293  Expression indexExpression = indices[i];
2294  for (int j = i + 1; j < indices.Count; j++)
2295  {
2296  var nextExpression = arrayType.Dimensions[j];
2297  indexExpression = new BinaryExpression(BinaryOperator.Multiply, indexExpression, nextExpression);
2298  }
2299 
2300  finalIndex = finalIndex == null ? indexExpression : new BinaryExpression(BinaryOperator.Plus, finalIndex, indexExpression);
2301  }
2302 
2303  // Return a 1d indexer
2304  indexerExpression = new IndexerExpression(targetIterator, finalIndex);
2305  }
2306  }
2307 
2308  Visit((Node)indexerExpression);
2309 
2310  // When NoSwapForBinaryMatrixOperation, we need to transpose accessor
2311  // HLSL: float4x3[0] -> first row -> float4(...)
2312  // GLSL: mat4x3[0] -> first column -> float4x3[0] = vec4(mat4x3[0][0], mat4x3[1][0], mat4x3[2][0], mat4x3[3][0]);
2313  if (matrixType != null && NoSwapForBinaryMatrixOperation && !isAssignmentTarget)
2314  {
2315  if (indices.Count == 2)
2316  {
2317  IndexerExpression nextExpression = null;
2318 
2319  // float4x3[0][1] -> mat4x3[1][0]
2320  for (int i = 0; i < indices.Count; i++)
2321  {
2322  nextExpression = nextExpression == null ? new IndexerExpression(variableReferenceExpression, indices[i]) : new IndexerExpression(nextExpression, indices[i]);
2323  }
2324  return nextExpression;
2325  }
2326  else
2327  {
2328  // matrixType.ColumnCount
2329  var matrixElementType = matrixType.Type.ResolveType() as ScalarType;
2330  var matrixRowType = new VectorType(matrixElementType, matrixType.ColumnCount);
2331 
2332  var convertRowToColumnMethod = new MethodInvocationExpression(new TypeReferenceExpression(matrixRowType));
2333 
2334  for (int i = 0; i < matrixType.ColumnCount; i++)
2335  {
2336  convertRowToColumnMethod.Arguments.Add(new IndexerExpression(new IndexerExpression(indexerExpression.Target, new LiteralExpression(i)), indexerExpression.Index));
2337  }
2338  return convertRowToColumnMethod;
2339  }
2340  }
2341 
2342  return indexerExpression;
2343  }
2344 
2345  private void GenerateSamplerMappingAndStrip()
2346  {
2347  //var samplerMappingVisitor = new SamplerMappingVisitor(samplerMapping);
2348  var samplerMappingVisitor = new SamplerMappingVisitor(shader, samplerMapping)
2349  {
2350  TextureFunctionsCompatibilityProfile = TextureFunctionsCompatibilityProfile
2351  };
2352  samplerMappingVisitor.Run((MethodDefinition)entryPoint);
2353 
2354  // Use the strip visitor in order to remove unused functions/declaration
2355  // from the entrypoint
2356  var stripVisitor = new StripVisitor(entryPointName);
2357  stripVisitor.KeepConstantBuffers = KeepConstantBuffer;
2358  stripVisitor.Visit(shader);
2359 
2360  // Then add the newly created variable
2361  foreach (var textureSampler in samplerMapping)
2362  {
2363  declarationListToRemove.Add(textureSampler.Key.Sampler);
2364  declarationListToRemove.Add(textureSampler.Key.Texture);
2365  AddGlobalDeclaration(textureSampler.Value);
2366  }
2367  }
2368 
2369  /// <summary>
2370  /// Visits the specified shader.
2371  /// </summary>
2372  /// <param name="shader">The shader.</param>
2373  [Visit]
2374  protected void Visit(Shader shader)
2375  {
2376  geometryLayoutInput = null;
2377  geometryInputParameter = null;
2378  geometryLayoutOutput = null;
2379 
2380  // Remove all texture and samplers. They will be added again as they are referenced (this is because sampler+texture becomes a sampler in OpenGL).
2381  // shader.Declarations.RemoveAll(x => x is SamplerType);
2382  // shader.Declarations.RemoveAll(x => x is TextureType);
2383 
2384  // Visit AST.
2385  Visit((Node)shader);
2386 
2387  // Post transform all array variable with multidimension
2388  TransformArrayDimensions();
2389 
2390  // Add explicit layout for ConstantBuffers
2391  foreach (var cBuffer in shader.Declarations.OfType<ConstantBuffer>())
2392  {
2393  AddExplicitLayout(cBuffer);
2394  }
2395 
2396  // Add uniform keyword to variables.
2397  foreach (var variable in shader.Declarations.OfType<Variable>())
2398  {
2399  var layoutRule = this.GetTagLayout(variable);
2400  bool isUniform = IsUniformLike(variable);
2401 
2402  // Uniforms used as global temporary are not tagged as uniforms
2403  if (!globalUniformVisitor.IsVariableAsGlobalTemporary(variable))
2404  {
2405  if (isUniform)
2406  {
2407  variable.Qualifiers |= Ast.StorageQualifier.Uniform;
2408 
2409  // For arrays, remove initializers if configured
2410  var variableArrayType = variable.Type.ResolveType() as ArrayType;
2411  if (variableArrayType != null && variable.InitialValue != null && !KeepUniformArrayInitializers)
2412  {
2413  variable.InitialValue = null;
2414  }
2415 
2416  if (UseBindingLayout)
2417  AddExplicitLayout(variable);
2418  }
2419  else
2420  {
2421  if (UseLocationLayout && layoutRule.Location != null)
2422  {
2423  layoutRule.Qualifier.Layouts.Add(new LayoutKeyValue("location", layoutRule.Location));
2424  }
2425  }
2426  }
2427 
2428  // Remove HLSL Register
2429  variable.Qualifiers.Values.RemoveAll(qualifierType => qualifierType is RegisterLocation);
2430  variable.Qualifiers.Values.Remove(Ast.Hlsl.StorageQualifier.Static);
2431  variable.Qualifiers.Values.Remove(Ast.Hlsl.StorageQualifier.Shared);
2432 
2433  // If variable is an object type, remove any initial values
2434  var type = variable.Type.ResolveType();
2435  if (type is ObjectType)
2436  variable.InitialValue = null;
2437  }
2438 
2439  // Add implicit layout for uniforms
2440  if (UseBindingLayout)
2441  {
2442  foreach (var variable in shader.Declarations.OfType<Variable>())
2443  {
2444  if (variable.Qualifiers.Contains(Ast.StorageQualifier.Uniform))
2445  {
2446  // GLSL doesn't support initial values for uniforms, so we are removing them
2447  // Errata: A third party GLSL compiler is supporting initial values, so we don't need to remove them
2448  // variable.InitialValue = null;
2449  AddImplicitLayout(variable);
2450  }
2451  }
2452  }
2453 
2454  // Add all defined layouts to the variable's qualifiers
2455  foreach (var variable in shader.Declarations.OfType<Variable>())
2456  {
2457  var layoutRule = this.GetTagLayout(variable);
2458 
2459  // If there is any explicit layout, we have to add them to the variable
2460  if (layoutRule.Qualifier.Layouts.Count > 0)
2461  variable.Qualifiers.Values.Insert(0, layoutRule.Qualifier);
2462 
2463  // Replace type if needed
2464  if (layoutRule.Type != null)
2465  variable.Type = new TypeName(layoutRule.Type) { Span = variable.Type.Span };
2466 
2467  if (layoutRule.Name != null && variable.Name.Text != layoutRule.Name)
2468  variable.Name = new Identifier(layoutRule.Name);
2469  }
2470 
2471  // Geometry shader specific analysis (in/out layouts).
2472  if (pipelineStage == PipelineStage.Geometry)
2473  {
2474  if (geometryLayoutInput != null)
2475  {
2476  // Add layout(XXX) in; to the geometry shader
2477  AddGeometryShaderInputDeclaration();
2478  AddGlobalDeclaration(new Variable(new TypeName(string.Format("layout({0})", geometryLayoutInput)), "in"));
2479  }
2480 
2481  var maxVertexCount = entryPoint.Attributes().FirstOrDefault(x => x.Name == "maxvertexcount");
2482  if (maxVertexCount != null && geometryLayoutOutput != null)
2483  {
2484  entryPoint.Attributes.Remove(maxVertexCount);
2485 
2486  // Add layout(XXX, max_vertices=Y) out; to the geometry shader
2487  AddGlobalDeclaration(new Variable(new TypeName(string.Format("layout({0}, max_vertices={1})", geometryLayoutOutput, maxVertexCount.Parameters[0])), "out"));
2488  }
2489  }
2490 
2491  // If there is any global uniforms used as local uniforms, we need to create locals
2492  foreach (var globalToLocalVariable in inputAssignment)
2493  {
2494  var globalVariable = globalToLocalVariable.Key;
2495  var localVariable = globalToLocalVariable.Value;
2496  int indexOfVariable = shader.Declarations.IndexOf(globalVariable) + 1;
2497 
2498  entryPoint.Body.Statements.Insert(0, new ExpressionStatement(new AssignmentExpression(AssignmentOperator.Default,
2499  new VariableReferenceExpression(localVariable),
2500  localVariable.InitialValue as VariableReferenceExpression) { Span = globalVariable.Span }));
2501 
2502  localVariable.InitialValue = null;
2503  shader.Declarations.Insert(indexOfVariable, new DeclarationStatement(localVariable) { Span = globalVariable.Span });
2504  }
2505 
2506  // Remove all texture and sampler declarations
2507  RemoveTextureAndSamplerDeclarations();
2508 
2509  // Transform all input/output to interface block if enabled
2510  TransformInputAndOutputToInterfaceBlock();
2511 
2512  // Clear all semantic information.
2513  foreach (var structureType in shader.Declarations.OfType<StructType>())
2514  {
2515  if (structureType is Ast.Glsl.InterfaceType)
2516  continue;
2517 
2518  foreach (var fieldRef in GetMembers(structureType))
2519  {
2520  var field = fieldRef.Field;
2521  field.Qualifiers = Qualifier.None;
2522  }
2523  }
2524 
2525  // Remove all arguments from main.
2526  entryPoint.Parameters.Clear();
2527 
2528  // Change main definition to be void main()
2529  entryPoint.Qualifiers = Qualifier.None;
2530  entryPoint.ReturnType = TypeBase.Void;
2531  entryPoint.Name = new Identifier("main");
2532  }
2533 
2534  private void TransformInputAndOutputToInterfaceBlock()
2535  {
2536  // Transform all variables with Interface block type if enabled
2537  if (!UseInterfaceForInOut && pipelineStage != PipelineStage.Geometry)
2538  return;
2539 
2540  var interfaceIn = new Ast.Glsl.InterfaceType(VertexIOInterfaceName) {Qualifiers = Ast.ParameterQualifier.In};
2541 
2542  var interfaceOut = new Ast.Glsl.InterfaceType(VertexIOInterfaceName) {Qualifiers = Ast.ParameterQualifier.Out};
2543 
2544  var isInAllowed = pipelineStage != PipelineStage.Vertex && pipelineStage != PipelineStage.Geometry;
2545  var isOutAllowed = pipelineStage != PipelineStage.Pixel;
2546 
2547  for (int i = shader.Declarations.Count - 1; i >= 0; i--)
2548  {
2549  var variable = shader.Declarations[i] as Variable;
2550  if (variable == null || variable.Type is Ast.Glsl.InterfaceType)
2551  continue;
2552 
2553  if (isInAllowed && variable.Qualifiers.Contains(Ast.ParameterQualifier.In))
2554  {
2555  variable.Qualifiers.Values.Remove(Ast.ParameterQualifier.In);
2556  interfaceIn.Fields.Insert(0, variable);
2557  shader.Declarations.RemoveAt(i);
2558  }
2559  else if (isOutAllowed && variable.Qualifiers.Contains(Ast.ParameterQualifier.Out))
2560  {
2561  variable.Qualifiers.Values.Remove(Ast.ParameterQualifier.Out);
2562  interfaceOut.Fields.Insert(0, variable);
2563  shader.Declarations.RemoveAt(i);
2564  }
2565  }
2566 
2567 
2568  var index = shader.Declarations.IndexOf(entryPoint);
2569  if (interfaceOut.Fields.Count > 0)
2570  shader.Declarations.Insert(index, interfaceOut);
2571 
2572  if (interfaceIn.Fields.Count > 0)
2573  shader.Declarations.Insert(index, interfaceIn);
2574  }
2575 
2576 
2577  private void AddGeometryShaderInputDeclaration()
2578  {
2579  // Convert a HLSL struct like struct VertexData { float2 texCoord; float3 normal; }
2580  // triangle VertexData input[3];
2581 
2582  // in _VertexData_ {
2583  // vec2 texCoord;
2584  // vec3 normal;
2585  // } input[];
2586 
2587  // TODO ADD CHECKING
2588  var arrayType = (ArrayType) geometryInputParameter.Type;
2589  var structType = arrayType.Type.TypeInference.TargetType as StructType;
2590  var interfaceType = new Ast.Glsl.InterfaceType { Name = VertexIOInterfaceName };
2591  int location = 0;
2592  var evaluator = new ExpressionEvaluator();
2593  var result = evaluator.Evaluate(arrayType.Dimensions[0]);
2594 
2595  int arrayLength = 0;
2596  if (result.HasErrors)
2597  {
2598  result.CopyTo(parserResult);
2599  }
2600  else
2601  {
2602  arrayLength = Convert.ToInt32(result.Value);
2603  }
2604 
2605  if (structType != null)
2606  {
2607  int insertPosition = 0;
2608  // Insert the variable to declare
2609  geometryInputParameter.Qualifiers = Qualifier.None;
2610  entryPoint.Body.Statements.Insert(insertPosition, new DeclarationStatement(geometryInputParameter));
2611  insertPosition++;
2612 
2613  const string GSInputName = "_gs_input_";
2614 
2615  for (int i = 0; i < arrayLength; i++)
2616  {
2617  foreach (var field in structType.Fields)
2618  {
2619  var dest = new MemberReferenceExpression(new IndexerExpression(new VariableReferenceExpression(geometryInputParameter), new LiteralExpression(i)), field.Name);
2620 
2622 
2623  var glVariableName = GetGlVariableNameFromSemantic(field.Semantic(), true);
2624  if (glVariableName != null && glVariableName.StartsWith("gl_"))
2625  {
2626  var newIndexerExpression = new IndexerExpression(new VariableReferenceExpression("gl_in"), new LiteralExpression(i));
2627  src = new MemberReferenceExpression(newIndexerExpression, glVariableName);
2628  }
2629  else
2630  {
2631  // For the first loop, generate the interface type
2632  if (i == 0)
2633  {
2634  var variable = field.DeepClone();
2635  if (UseLocationLayout)
2636  {
2637  var variableTag = this.GetTagLayout(variable);
2638 
2639  if (variableTag.Location == null)
2640  {
2641  if (UseSemanticForLocation)
2642  {
2643  variableTag.Location = "S_" + variable.Semantic().Name.Text;
2644  }
2645  else
2646  {
2647  variableTag.Location = location;
2648  }
2649 
2650  location++;
2651  }
2652 
2653  variableTag.Qualifier.Layouts.Add(new LayoutKeyValue("location", variableTag.Location));
2654 
2655  variable.Qualifiers = Qualifier.None;
2656  variable.Qualifiers |= variableTag.Qualifier;
2657  }
2658  interfaceType.Fields.Add(variable);
2659  }
2660 
2661  src = new MemberReferenceExpression(new IndexerExpression(new VariableReferenceExpression(GSInputName), new LiteralExpression(i)), field.Name);
2662  }
2663 
2664  entryPoint.Body.Statements.Insert(insertPosition, new ExpressionStatement(new AssignmentExpression(AssignmentOperator.Default, dest, src)));
2665  insertPosition++;
2666  }
2667  }
2668 
2669  var globalInterfaceType = new Variable(new ArrayType(interfaceType, new EmptyExpression()), GSInputName) { Qualifiers = Ast.ParameterQualifier.In };
2670 
2671  AddGlobalDeclaration(globalInterfaceType);
2672  }
2673  }
2674 
2675  private void RemoveTextureAndSamplerDeclarations()
2676  {
2677  // Remove all texture declaration and sampler declaration
2678  shader.Declarations.RemoveAll(x => (x is Variable) && (((Variable)x).Type is TextureType));
2679  shader.Declarations.RemoveAll(declarationListToRemove.Contains);
2680 
2681  SearchVisitor.Run(
2682  shader,
2683  node =>
2684  {
2685  var variable = node as Variable;
2686  if (variable != null)
2687  {
2688  var variableRef = variable.InitialValue as VariableReferenceExpression;
2689  if (variable.Type is TextureType || (variableRef != null && declarationListToRemove.Contains(variableRef.TypeInference.Declaration)))
2690  {
2691  return null;
2692  }
2693  }
2694  return node;
2695  });
2696  }
2697 
2698 
2699 
2700  /// <summary>
2701  /// Visits the specified parenthesized expression.
2702  /// </summary>
2703  /// <param name="parenthesizedExpression">The parenthesized expression.</param>
2704  /// <returns>A transformed expression.</returns>
2705  [Visit]
2706  protected virtual Expression Visit(ParenthesizedExpression parenthesizedExpression)
2707  {
2708  Visit((Node)parenthesizedExpression);
2709 
2710  // Copy back type inference target type to parennthesized expression
2711  parenthesizedExpression.TypeInference.TargetType = parenthesizedExpression.Content.TypeInference.TargetType;
2712 
2713  // As it is not supported by opengl, return the last element of the list for multiple arguments
2714  // when cast expression is used with an expression list
2715  if (parenthesizedExpression.Content is ExpressionList && ParentNode is CastExpression)
2716  {
2717  var expressionList = (ExpressionList)parenthesizedExpression.Content;
2718  return ConvertToSafeExpressionForBinary(expressionList[expressionList.Count - 1]);
2719  }
2720 
2721  // else return the parenthesized as-is
2722  return parenthesizedExpression;
2723  }
2724 
2725  /// <summary>
2726  /// Splits typedefs declaration when a struct inline is used as the type
2727  /// </summary>
2728  private void SplitTypeDefs()
2729  {
2730  var newDeclarations = new List<Node>();
2731  foreach (var declaration in this.shader.Declarations)
2732  {
2733  var typedef = declaration as Typedef;
2734  if (typedef != null && typedef.Type is StructType)
2735  {
2736  var structType = typedef.Type as StructType;
2737  if (typedef.Type.Name == null)
2738  {
2739  typedef.Type.Name = (typedef.IsGroup ? typedef.SubDeclarators[0].Name : typedef.Name) + "_";
2740  }
2741  newDeclarations.Add(typedef.Type);
2742 
2743  typedef.Type = new TypeName(typedef.Type.Name) { TypeInference = { Declaration = structType, TargetType = typedef.Type } };
2744 
2745  if (typedef.IsGroup)
2746  {
2747  foreach (var typedefDeclarator in typedef.SubDeclarators)
2748  {
2749  typedefDeclarator.TypeInference.Declaration = structType;
2750  typedefDeclarator.TypeInference.TargetType = structType;
2751  }
2752  }
2753  else
2754  {
2755  typedef.TypeInference.Declaration = structType;
2756  typedef.TypeInference.TargetType = structType;
2757  }
2758 
2759  newDeclarations.Add(typedef);
2760  }
2761  else
2762  {
2763  newDeclarations.Add(declaration);
2764  }
2765  }
2766  shader.Declarations = newDeclarations;
2767  }
2768 
2769  /// <summary>
2770  /// Allocates the new binding.
2771  /// </summary>
2772  /// <param name="allocatedRegisters">
2773  /// The allocated registers.
2774  /// </param>
2775  /// <param name="startingIndex">
2776  /// Index of the starting.
2777  /// </param>
2778  /// <param name="sizeOfAllocation">
2779  /// The size of allocation.
2780  /// </param>
2781  private static void AllocateNewBinding(bool[] allocatedRegisters, int startingIndex, int sizeOfAllocation)
2782  {
2783  for (int i = 0; i < sizeOfAllocation; i++)
2784  allocatedRegisters[startingIndex + i] = true;
2785  }
2786 
2787  /// <summary>
2788  /// Converts to specified expression to a safe expression for binary operation.
2789  /// </summary>
2790  /// <param name="expression">
2791  /// The expression.
2792  /// </param>
2793  /// <returns>
2794  /// If the expression was a binary expression, then it is embraced by a <see cref="ParenthesizedExpression"/>
2795  /// </returns>
2796  private static Expression ConvertToSafeExpressionForBinary(Expression expression)
2797  {
2798  if (expression is BinaryExpression || expression is ConditionalExpression)
2799  return new ParenthesizedExpression(expression);
2800  return expression;
2801  }
2802 
2803  /// <summary>
2804  /// Finds the available binding.
2805  /// </summary>
2806  /// <param name="allocatedRegisters">
2807  /// The allocated registers.
2808  /// </param>
2809  /// <param name="startingIndex">
2810  /// Index of the starting.
2811  /// </param>
2812  /// <param name="sizeOfAllocation">
2813  /// The size of allocation.
2814  /// </param>
2815  /// <returns>
2816  /// The find available binding.
2817  /// </returns>
2818  private static int FindAvailableBinding(bool[] allocatedRegisters, int startingIndex, int sizeOfAllocation)
2819  {
2820  int newIndex = -1;
2821  int allocSize = sizeOfAllocation;
2822  for (int i = startingIndex; i < allocatedRegisters.Length; i++)
2823  {
2824  if (allocatedRegisters[i])
2825  {
2826  newIndex = -1;
2827  allocSize = sizeOfAllocation;
2828  }
2829  else
2830  {
2831  if (newIndex < 0)
2832  newIndex = i;
2833  allocSize--;
2834  if (allocSize == 0)
2835  break;
2836  }
2837  }
2838 
2839  // Only return selected Index if we were able to allocate sizeOfAllocation
2840  if (allocSize == 0)
2841  return newIndex;
2842 
2843  return -1;
2844  }
2845 
2846  /// <summary>
2847  /// Determines whether the specified variable is an uniform like.
2848  /// </summary>
2849  /// <param name="variable">
2850  /// The variable.
2851  /// </param>
2852  /// <returns>
2853  /// <c>true</c> if the specified variable is an uniform like; otherwise, <c>false</c>.
2854  /// </returns>
2855  private static bool IsUniformLike(Variable variable)
2856  {
2857  return !variable.Qualifiers.Contains(Ast.ParameterQualifier.InOut) && !variable.Qualifiers.Contains(Ast.ParameterQualifier.In) && !variable.Qualifiers.Contains(Ast.ParameterQualifier.Out)
2858  && !variable.Qualifiers.Contains(Ast.Hlsl.StorageQualifier.Static) && !variable.Qualifiers.Contains(Ast.StorageQualifier.Const);
2859  }
2860 
2861  /// <summary>
2862  /// Convert semantic string into a (semantic, semanticIndex) pair.
2863  /// </summary>
2864  /// <param name="semantic">
2865  /// The semantic.
2866  /// </param>
2867  /// <returns>
2868  /// A KeyvalueParis semantic -&gt; location
2869  /// </returns>
2870  private static KeyValuePair<string, int> ParseSemantic(string semantic)
2871  {
2872  // A semantic can have a modifier. We parse it but we don't handle it
2873  // http://msdn.microsoft.com/en-us/library/bb219850%28v=vs.85%29.aspx
2874  foreach (var semanticModifier in SemanticModifiers)
2875  {
2876  if (semantic.ToLower().EndsWith(semanticModifier))
2877  {
2878  // Console.WriteLine("Warning, unsupported semantic modifier [{0}] for semantic [{1}]", semanticModifier, semantic);
2879  semantic = semantic.Substring(0, semantic.Length - semanticModifier.Length);
2880  break;
2881  }
2882  }
2883 
2884  return Semantic.Parse(semantic);
2885  }
2886 
2887  /// <summary>
2888  /// Adds the explicit layout.
2889  /// </summary>
2890  /// <param name="variable">
2891  /// The variable.
2892  /// </param>
2893  private void AddExplicitLayout(Variable variable)
2894  {
2895  var layout = this.GetTagLayout(variable);
2896  var registerLocation = variable.Qualifiers.Values.OfType<RegisterLocation>().FirstOrDefault();
2897 
2898  if (registerLocation != null && layout.Binding == null)
2899  {
2900  int registerIndex;
2901  var register = registerLocation.Register.Text;
2902 
2903  var allocatedRegister = register.StartsWith("s") ? allocatedRegistersForSamplers : allocatedRegistersForUniforms;
2904  string registerIndexStr = register[1] != '[' ? register.Substring(1) : register.Substring(2, register.Length - 3);
2905 
2906  if (!int.TryParse(registerIndexStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out registerIndex))
2907  {
2908  parserResult.Error("Invalid layout binding for variable [{0}]", variable.Span, variable);
2909  return;
2910  }
2911 
2912  var size = GetNumberOfFloat4FromVariable(variable.Type);
2913 
2914  var newIndex = FindAvailableBinding(allocatedRegister, registerIndex, size);
2915 
2916  // If this register index was already allocated, try to allocate the new register as an implicit layout
2917  if (newIndex != registerIndex)
2918  {
2919  parserResult.Warning("Unable to use explicit layout for variable {0} as the location is already used. Use of an implicit layout", variable.Span, variable);
2920  AddImplicitLayout(variable);
2921  }
2922  else
2923  {
2924  AllocateNewBinding(allocatedRegister, registerIndex, size);
2925  layout.Binding = registerIndex;
2926  layout.Qualifier.Layouts.Add(new LayoutKeyValue("binding", registerIndex));
2927  }
2928  }
2929  }
2930 
2931  /// <summary>
2932  /// Adds the explicit layout for a constant buffer.
2933  /// </summary>
2934  /// <param name="cBuffer">The variable.</param>
2935  private void AddExplicitLayout(ConstantBuffer cBuffer)
2936  {
2937  // Clear old register
2938  var register = cBuffer.Register;
2939  cBuffer.Register = null;
2940 
2941  // If a register was defined
2942  if (register != null)
2943  {
2944  var registerStr = register.Register.Text;
2945 
2946  var layout = this.GetTagLayout(cBuffer, registerStr);
2947 
2948  if (registerStr.StartsWith("b"))
2949  {
2950  int registerIndex;
2951  string registerIndexStr = registerStr.Substring(1);
2952 
2953  if (!int.TryParse(registerIndexStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out registerIndex))
2954  {
2955  parserResult.Error("Invalid layout binding for Constant Buffer [{0}]", cBuffer.Span, cBuffer);
2956  return;
2957  }
2958 
2959  // A third party GLSL compiler requires layout binding to start at 1-15
2960  registerIndex++;
2961 
2962  if (layout.Binding == null)
2963  layout.Binding = registerIndex;
2964  }
2965 
2966  if (layout.Binding != null)
2967  {
2968  cBuffer.Register = new RegisterLocation(string.Empty, layout.Binding.ToString());
2969  }
2970  }
2971 
2972  // Add Location layout from packoffset for constant buffers/uniform blocks
2973  if (UseLocationLayout)
2974  {
2975  foreach (var variable in cBuffer.Members.OfType<Variable>())
2976  {
2977  var packOffset = variable.Qualifiers.OfType<PackOffset>().FirstOrDefault();
2978 
2979  if (packOffset != null)
2980  {
2981  variable.Qualifiers = Qualifier.None;
2982  variable.Qualifiers |= new Ast.Glsl.LayoutQualifier(new LayoutKeyValue("location", packOffset.ToFloat4SlotIndex()));
2983  }
2984  }
2985  }
2986  }
2987 
2988  /// <summary>
2989  /// Adds the global declaration.
2990  /// </summary>
2991  /// <typeparam name="T">
2992  /// Type of the declaration
2993  /// </typeparam>
2994  /// <param name="declaration">
2995  /// The declaration.
2996  /// </param>
2997  private void AddGlobalDeclaration<T>(T declaration, bool forceToAdd = false) where T : Node, IDeclaration
2998  {
2999  // Don't add glsl variable
3000  if (!declaration.Name.Text.StartsWith("gl_") || forceToAdd)
3001  {
3002  var index = shader.Declarations.IndexOf(entryPoint);
3003  shader.Declarations.Insert(index, declaration);
3004  }
3005 
3006  var topStack = ScopeStack.LastOrDefault();
3007  if (topStack != null)
3008  topStack.AddDeclaration(declaration);
3009  }
3010 
3011  /// <summary>
3012  /// Adds the implicit layout.
3013  /// </summary>
3014  /// <param name="variable">
3015  /// The variable.
3016  /// </param>
3017  private void AddImplicitLayout(Variable variable)
3018  {
3019  var registerLocation = variable.Qualifiers.Values.OfType<RegisterLocation>().FirstOrDefault();
3020  var layout = this.GetTagLayout(variable);
3021 
3022  if (registerLocation == null && layout.Binding == null)
3023  {
3024  // Remove any kind of register location
3025  // if (forceImplicitLayout)
3026  // variable.Qualifiers.Values.RemoveAll((type) => type is RegisterLocation);
3027  var allocatedRegister = variable.Type is SamplerType ? allocatedRegistersForSamplers : allocatedRegistersForUniforms;
3028  var size = GetNumberOfFloat4FromVariable(variable.Type);
3029 
3030  int registerIndex = FindAvailableBinding(allocatedRegister, 0, size);
3031 
3032  // if (layout.Layout.Binding.HasValue)
3033  // registerIndex = layout.Layout.Binding.Value;
3034  if (registerIndex < 0)
3035  parserResult.Error("Unable to find a free slot for uniform {0}", variable.Span, variable);
3036  else
3037  {
3038  AllocateNewBinding(allocatedRegister, registerIndex, size);
3039  layout.Binding = registerIndex;
3040  layout.Qualifier.Layouts.Add(new LayoutKeyValue("binding", registerIndex));
3041  }
3042  }
3043  }
3044 
3045  /// <summary>
3046  /// Binds the location.
3047  /// </summary>
3048  /// <param name="semantic">The semantic.</param>
3049  /// <param name="typebase">The typebase.</param>
3050  /// <param name="isInput">if set to <c>true</c> [is input].</param>
3051  /// <param name="defaultName">The default name.</param>
3052  /// <param name="location">The location.</param>
3053  /// <returns>
3054  /// A variable
3055  /// </returns>
3056  private Variable BindLocation(Semantic semantic, TypeBase typebase, bool isInput, string defaultName, ref int location, SourceSpan span)
3057  {
3058  var variableFromSemantic = GetVariableFromSemantic(semantic, typebase, isInput, defaultName, span);
3059  if (!variableFromSemantic.Name.Text.StartsWith("gl_"))
3060  {
3061  var variableTag = this.GetTagLayout(variableFromSemantic);
3062 
3063  if (variableTag.Location == null)
3064  {
3065  if (UseSemanticForLocation)
3066  {
3067  variableTag.Location = "S_" + semantic.Name.Text;
3068  }
3069  else
3070  {
3071  variableTag.Location = location;
3072  }
3073 
3074  location++;
3075  }
3076  }
3077 
3078  return variableFromSemantic;
3079  }
3080 
3081  /// <summary>
3082  /// Calculates the GLSL prefix.
3083  /// </summary>
3084  /// <param name="type">
3085  /// The type.
3086  /// </param>
3087  /// <returns>
3088  /// The prefix of the glsl variable
3089  /// </returns>
3090  private string CalculateGlslPrefix(ScalarType type)
3091  {
3092  string prefix = string.Empty;
3093  if (type == ScalarType.Float || type == ScalarType.Half)
3094  prefix = string.Empty;
3095  else if (type == ScalarType.Bool)
3096  prefix = "b";
3097  else if (type == ScalarType.Int)
3098  prefix = "i";
3099  else if (type == ScalarType.UInt)
3100  prefix = "u";
3101  else if (type == ScalarType.Double)
3102  prefix = "d";
3103  return prefix;
3104  }
3105 
3106  /// <summary>
3107  /// Checks a cast method.
3108  /// </summary>
3109  /// <param name="methodInvocationExpression">
3110  /// The method invocation expression.
3111  /// </param>
3112  private void CheckCastMethod(MethodInvocationExpression methodInvocationExpression)
3113  {
3114  var typeReferenceExpression = methodInvocationExpression.Target as TypeReferenceExpression;
3115  if (typeReferenceExpression != null)
3116  {
3117  // Transform vector to array initializer:
3118  // float value[4] = float[4](myVectorFloat4); to => float value[4] = float[4](myVectorFloat4[0], myVectorFloat4[1], myVectorFloat4[2], myVectorFloat4[3]);
3119  var arrayType = typeReferenceExpression.Type as ArrayType;
3120  if (arrayType != null)
3121  {
3122  if (methodInvocationExpression.Arguments.Count == 1)
3123  {
3124  var argument = methodInvocationExpression.Arguments[0];
3125  methodInvocationExpression.Arguments.Clear();
3126 
3127  var argType = argument.TypeInference.TargetType;
3128  var arrayElementType = arrayType.Type.ResolveType();
3129  if (argType is VectorType && arrayElementType is ScalarType && arrayType.Dimensions.Count == 1)
3130  {
3131  var vectorType = (VectorType)argType;
3132 
3133  for (int i = 0; i < vectorType.Dimension; i++)
3134  {
3135  Expression indexerExpression = new IndexerExpression(argument, new LiteralExpression(i)) { TypeInference = { TargetType = arrayElementType } };
3136 
3137  if (vectorType.Type != arrayElementType)
3138  indexerExpression = new MethodInvocationExpression(new TypeReferenceExpression(arrayElementType), indexerExpression);
3139 
3140  methodInvocationExpression.Arguments.Add(indexerExpression);
3141  }
3142  }
3143  }
3144  }
3145  }
3146  }
3147 
3148  /// <summary>
3149  /// Converts the condition.
3150  /// </summary>
3151  /// <param name="expression">
3152  /// The expression.
3153  /// </param>
3154  /// <returns>
3155  /// A converted expression
3156  /// </returns>
3157  private Expression ConvertCondition(Expression expression)
3158  {
3159  var expressionType = expression.TypeInference.TargetType;
3160  // Convert !value, with value not bool to int(value) == 0
3161  if (expressionType != ScalarType.Bool)
3162  {
3163  expression = new MethodInvocationExpression(new TypeReferenceExpression(ScalarType.Bool), expression) { TypeInference = { TargetType = ScalarType.Bool } };
3164  }
3165  return expression;
3166  }
3167 
3168 
3169  private Expression CastSemanticToReferenceType(Identifier name, TypeBase semanticType, Variable semanticAsVariable)
3170  {
3171  TypeBase glslType = semanticAsVariable.Type;
3172 
3173  var defaultGlslRef = new VariableReferenceExpression(name) { TypeInference = { Declaration = semanticAsVariable, TargetType = glslType } };
3174 
3175  var semanticVectorType = semanticType as VectorType;
3176  var glslVectorType = glslType as VectorType;
3177  if (semanticVectorType != null && glslVectorType != null)
3178  {
3179  if (semanticVectorType.Dimension < glslVectorType.Dimension)
3180  {
3181  return new MemberReferenceExpression(defaultGlslRef, "xyzw".Substring(0, semanticVectorType.Dimension)) { TypeInference = { TargetType = semanticVectorType } };
3182  }
3183 
3184  if (semanticVectorType.Dimension > glslVectorType.Dimension)
3185  {
3186  // TODO: Is this case is relevant?
3187  }
3188  }
3189 
3190  return defaultGlslRef;
3191  }
3192 
3193  private Expression ConvertReferenceToSemantics(VariableReferenceExpression varRefExpr, Semantic semantic, TypeBase type, string varName, SourceSpan span)
3194  {
3195  // Detect and transform input/output structure member reference.
3196  // i.e. output.position should get transformed to gl_Position
3197  if (varRefExpr != null)
3198  {
3199  bool isInputOrOutput = false;
3200 
3201  if (IsInEntryPoint && (semantic != null || (type != null && type is StructType)))
3202  {
3203  bool isInput = inputs.Any(x => x.Name == varRefExpr.Name);
3204  bool isOutput = outputs.Any(x => x.Name == varRefExpr.Name);
3205 
3206  isInputOrOutput = isInput || isOutput;
3207 
3208  // if isInput and not StructType
3209  // if isOutput and not structType
3210  // if isOutput and structType && not assigntarget
3211  if (((isInput || isOutput) && !(type is StructType)) || (isOutput && !isAssignmentTarget))
3212  {
3213  var variable = GetVariableFromSemantic(semantic, type, isInput, varName, span );
3214  Variable newVariable;
3215  inputAssignment.TryGetValue(variable, out newVariable);
3216 
3217  if (isInput && isAssignmentTarget && newVariable == null)
3218  {
3219  newVariable = new Variable(variable.Type, "local_" + variable.Name.Text, CastSemanticToReferenceType(variable.Name, type, variable));
3220  inputAssignment.Add(variable, newVariable);
3221  return new VariableReferenceExpression(newVariable);
3222  }
3223 
3224  if (newVariable != null)
3225  variable = newVariable;
3226 
3227  return this.CastSemanticToReferenceType(variable.Name, type, variable);
3228  }
3229  }
3230 
3231  // Some uniforms have semantics attached, so if this is not an input or output variable, this is more likely to be an uniform
3232  if (!isInputOrOutput)
3233  {
3234  var variable = FindDeclaration(varRefExpr.Name) as Variable;
3235 
3236  if (variable != null)
3237  {
3238  Variable newVariable;
3239  inputAssignment.TryGetValue(variable, out newVariable);
3240  if (isAssignmentTarget && IsUniformLike(variable) && shader.Declarations.Contains(variable) && newVariable == null)
3241  {
3242  newVariable = new Variable(variable.Type, "local_" + variable.Name.Text, new VariableReferenceExpression(variable.Name) { TypeInference = { TargetType = variable.Type } });
3243  inputAssignment.Add(variable, newVariable);
3244  }
3245 
3246  if (newVariable != null)
3247  return new VariableReferenceExpression(newVariable.Name) { TypeInference = { TargetType = newVariable.Type.ResolveType() } };
3248  }
3249  }
3250  }
3251 
3252  return null;
3253  }
3254 
3255  private void ReturnStruct(StructType structType, Expression returnValueExpression, StatementList statementList)
3256  {
3257  var span = returnValueExpression.Span;
3258  foreach (var fieldRef in GetMembers(structType))
3259  {
3260  var field = fieldRef.Field;
3261 
3262 
3263  // When a field is an array, we need to properly handle return values for semantics
3264  var fieldType = field.Type.ResolveType();
3265  var fieldArrayType = fieldType as ArrayType;
3266 
3267  var semanticVariable = GetVariableFromSemantic(field.Semantic(), fieldType, false, fieldRef.FieldNamePath, span);
3268 
3269  // If this is a special semantic we need to convert each indices
3270  if (fieldArrayType != null && semanticVariable.Name.Text.StartsWith("gl_"))
3271  {
3272  var arrayDimension = fieldArrayType.Dimensions[0] as LiteralExpression;
3273  var arrayValue = arrayDimension != null ? Convert.ChangeType(arrayDimension.Literal.Value, typeof(int)) : null;
3274  if (arrayDimension != null && arrayValue != null)
3275  {
3276  var count = (int)arrayValue;
3277  for (int i = 0; i < count; i++)
3278  {
3279  var semantic = field.Semantic();
3280  var newSemantic = new Semantic(semantic.BaseName + i);
3281 
3282  statementList.Add(
3283  new ExpressionStatement(
3284  new AssignmentExpression(
3285  AssignmentOperator.Default,
3286  new VariableReferenceExpression(GetVariableFromSemantic(newSemantic, fieldArrayType, false, fieldRef.FieldNamePath, span).Name),
3287  new IndexerExpression(fieldRef.GetMemberReference(returnValueExpression), new LiteralExpression(i)))) { Span = span });
3288  }
3289 
3290  }
3291  else
3292  {
3293  parserResult.Error("Unable to convert semantic expression [{0}]. Array dimension must be a literal expression", field.Span, field);
3294  }
3295  }
3296  else
3297  {
3298  var semanticValue = (Expression)fieldRef.GetMemberReference(returnValueExpression);
3299  if (fieldType != semanticVariable.Type)
3300  {
3301  semanticValue = NewCast(semanticVariable.Type, semanticValue);
3302  }
3303 
3304  statementList.Add(
3305  new ExpressionStatement(
3306  new AssignmentExpression(
3307  AssignmentOperator.Default, new VariableReferenceExpression(semanticVariable.Name) { TypeInference = { Declaration = semanticVariable } }, semanticValue)) { Span = returnValueExpression.Span });
3308  }
3309  }
3310  }
3311 
3312  /// <summary>
3313  /// This helper function will transform a "return X;" statement into a list of assignment for each semantic and a "return;".
3314  /// </summary>
3315  /// <param name="returnValueExpression">
3316  /// The expression.
3317  /// </param>
3318  /// <param name="emitReturn">
3319  /// if set to <c>true</c> [emit return].
3320  /// </param>
3321  /// <returns>
3322  /// A statement used to replace the return statement
3323  /// </returns>
3324  private Statement ConvertReturn(Expression returnValueExpression, bool emitReturn, SourceSpan? span)
3325  {
3326  var statementList = new StatementList();
3327  Statement result = statementList;
3328 
3329  StructType structType = null;
3330 
3331  // Handle structure returned by variable
3332  if (returnValueExpression != null)
3333  {
3334  if (!span.HasValue)
3335  span = returnValueExpression.Span;
3336 
3337  var varRefExpr = returnValueExpression as VariableReferenceExpression;
3338  if (varRefExpr != null)
3339  {
3340  var variableDeclarator = varRefExpr.TypeInference.Declaration as Variable;
3341  structType = variableDeclarator != null ? variableDeclarator.Type.ResolveType() as StructType : null;
3342 
3343  if (structType != null)
3344  {
3345  ReturnStruct(structType, returnValueExpression, statementList);
3346  }
3347  }
3348  else
3349  {
3350  // Handle structure returned by method invocation
3351  var methodRefExp = returnValueExpression as MethodInvocationExpression;
3352  if (methodRefExp != null)
3353  {
3354  var variableDeclarator = methodRefExp.Target.TypeInference.Declaration as MethodDeclaration;
3355  structType = variableDeclarator != null ? variableDeclarator.ReturnType.ResolveType() as StructType : null;
3356  }
3357 
3358  if (structType != null)
3359  {
3360  // Replace plain statement list with a block statement
3361  result = new BlockStatement(statementList);
3362 
3363  statementList.Add(new DeclarationStatement(new Variable(new TypeName(structType.Name), "_local_ret_", returnValueExpression)));
3364 
3365  var localRet = new VariableReferenceExpression("_local_ret_");
3366 
3367  ReturnStruct(structType, localRet, statementList);
3368  }
3369  }
3370 
3371  if (CurrentFunction.Semantic() != null)
3372  {
3373  var semantic = CurrentFunction.Semantic();
3374  statementList.Add(
3375  new ExpressionStatement(
3376  new AssignmentExpression(
3377  AssignmentOperator.Default,
3378  new VariableReferenceExpression(GetVariableFromSemantic(semantic, CurrentFunction.ReturnType.ResolveType(), false, null, semantic.Span).Name),
3379  returnValueExpression)) { Span = span.Value } );
3380  }
3381  }
3382 
3383  // For structure in output, declare a local variable
3384  foreach (var variable in this.outputs)
3385  {
3386  structType = variable.Type.ResolveType() as StructType;
3387  if (structType != null)
3388  {
3389  // No modifiers for structure inlined in the code
3390  variable.Qualifiers = Qualifier.None;
3391  ReturnStruct(structType, new VariableReferenceExpression(variable.Name), statementList);
3392  }
3393  }
3394 
3395  // Remap Z coordinates
3396  this.RemapCoordinates(statementList);
3397 
3398  if (emitReturn)
3399  statementList.Add(new ReturnStatement() { Span = span.HasValue ? span.Value : new SourceSpan() });
3400 
3401  return result;
3402  }
3403 
3404  /// <summary>
3405  /// Finds the name of the type by its name.
3406  /// </summary>
3407  /// <param name="name">
3408  /// The name.
3409  /// </param>
3410  /// <returns>
3411  /// A type
3412  /// </returns>
3413  private TypeBase FindTypeByName(string name)
3414  {
3415  return FindDeclaration(name) as TypeBase;
3416  }
3417 
3418  /// <summary>
3419  /// Finds the vertex layout rule by semantic name.
3420  /// </summary>
3421  /// <param name="name">
3422  /// The name.
3423  /// </param>
3424  /// <returns>
3425  /// A <see cref="VariableLayoutRule"/>
3426  /// </returns>
3427  private VariableLayoutRule FindVariableLayoutBySemantic(string name)
3428  {
3429  VariableLayoutRule rule;
3430  this.VariableLayouts.TryGetValue(name, out rule);
3431  return rule;
3432  }
3433 
3434  /// <summary>
3435  /// Finds the vertex layout rule by semantic name.
3436  /// </summary>
3437  /// <param name="name">
3438  /// The name.
3439  /// </param>
3440  /// <returns>
3441  /// A <see cref="VariableLayoutRule"/>
3442  /// </returns>
3443  private ConstantBufferLayoutRule FindConstantBufferLayoutByRegister(string name)
3444  {
3445  ConstantBufferLayoutRule rule;
3446  this.ConstantBufferLayouts.TryGetValue(name, out rule);
3447  return rule;
3448  }
3449 
3450 
3451  /// <summary>
3452  /// Flattens the array creation expression.
3453  /// </summary>
3454  /// <param name="from">
3455  /// The source array that could be composed of inner array creation expression.
3456  /// </param>
3457  /// <param name="to">
3458  /// The destination array that will receive all flattened values
3459  /// </param>
3460  private void FlattenArrayCreationExpression(ArrayInitializerExpression from, List<Expression> to)
3461  {
3462  foreach (var nextElement in from.Items)
3463  {
3464  // Recursive call if there is an array creation expression.
3465  if (nextElement is ArrayInitializerExpression)
3466  FlattenArrayCreationExpression((ArrayInitializerExpression)nextElement, to);
3467  else
3468  to.Add(nextElement);
3469  }
3470  }
3471 
3472  private Variable FindGlobalVariableFromExpression(Expression expression)
3473  {
3474  var variableRef = expression as VariableReferenceExpression;
3475  if (variableRef != null)
3476  {
3477  var variable = variableRef.TypeInference.Declaration as Variable;
3478 
3479  if (variable != null)
3480  {
3481  // If a variable has an initial value, find the global variable
3482  if (!shader.Declarations.Contains(variable) && variable.InitialValue != null)
3483  {
3484  return this.FindGlobalVariableFromExpression(variable.InitialValue);
3485  }
3486 
3487  // Is this a global variable?
3488  if (shader.Declarations.Contains(variable))
3489  {
3490  return variable;
3491  }
3492  }
3493  }
3494  return null;
3495  }
3496 
3497  /// <summary>
3498  /// Gets the GL sampler associated with a sampler and a texture.
3499  /// </summary>
3500  /// <param name="sampler">The sampler.</param>
3501  /// <param name="texture">The texture.</param>
3502  /// <param name="forceNullSampler">if set to <c>true</c> [force null sampler] to match.</param>
3503  /// <returns>
3504  /// The variable associated with the sampler and the texture
3505  /// </returns>
3506  private Variable GetGLSampler(Variable sampler, Variable texture, bool forceNullSampler)
3507  {
3508  Variable glslSampler;
3509 
3510  if (sampler == null && !forceNullSampler)
3511  {
3512  // Access using only texture, any sampler/texture pair with matching texture is OK (in case forceNullSampler is not set)
3513  var matchingTextureSampler = samplerMapping.Where(x => x.Key.Texture == texture);
3514  if (!matchingTextureSampler.Any())
3515  {
3516  return null;
3517  }
3518 
3519  return matchingTextureSampler.First().Value;
3520  }
3521 
3522  var samplerKey = new SamplerTextureKey(sampler, texture);
3523  if (!samplerMapping.TryGetValue(samplerKey, out glslSampler))
3524  {
3525  return null;
3526  }
3527 
3528  return glslSampler;
3529  }
3530 
3531  /// <summary>
3532  /// Gets the number of float4 from a type.
3533  /// </summary>
3534  /// <param name="typeOfVar">
3535  /// The type.
3536  /// </param>
3537  /// <returns>
3538  /// Number of float4 from a type
3539  /// </returns>
3540  private int GetNumberOfFloat4FromVariable(TypeBase typeOfVar)
3541  {
3542  var variableType = typeOfVar.ResolveType();
3543 
3544  var matrixType = variableType as MatrixType;
3545  if (matrixType != null)
3546  return matrixType.RowCount * matrixType.ColumnCount / 4;
3547 
3548  var arrayType = variableType as ArrayType;
3549  if (arrayType != null)
3550  {
3551  // var dimExpr = arrayType.Dimensions[0] as LiteralExpression;
3552  var evaluator = new ExpressionEvaluator();
3553  var result = evaluator.Evaluate(arrayType.Dimensions[0]);
3554 
3555  if (result.HasErrors)
3556  {
3557  result.CopyTo(parserResult);
3558  }
3559  else
3560  {
3561  var dimValue = Convert.ToInt32(result.Value);
3562  return dimValue * GetNumberOfFloat4FromVariable(arrayType.Type);
3563  }
3564  }
3565 
3566  var structType = variableType as StructType;
3567  if (structType != null)
3568  {
3569  int structSize = 0;
3570  foreach (var variable in structType.Fields)
3571  {
3572  structSize += GetNumberOfFloat4FromVariable(variable.Type.ResolveType());
3573  }
3574  return structSize;
3575  }
3576 
3577  // Else default is 1 float4
3578  return 1;
3579  }
3580 
3581  /// <summary>
3582  /// Gets the variable from semantic.
3583  /// </summary>
3584  /// <param name="semantic">
3585  /// The semantic.
3586  /// </param>
3587  /// <param name="type">
3588  /// The type.
3589  /// </param>
3590  /// <param name="isInput">
3591  /// if set to <c>true</c> [is input].
3592  /// </param>
3593  /// <param name="varName">
3594  /// Name of the var.
3595  /// </param>
3596  /// <returns>
3597  /// The variable associated with a semantic
3598  /// </returns>
3599  private Variable GetVariableFromSemantic(Semantic semantic, TypeBase type, bool isInput, string varName, SourceSpan span)
3600  {
3601  type = type.ResolveType();
3602 
3603  bool isArray = type is ArrayType;
3604  TypeBase elementType = isArray ? ((ArrayType)type).Type.ResolveType() : type;
3605 
3606  TypeBase defaultType = type;
3607  int semanticIndex = 0;
3608 
3609  var glSemantic = semantic;
3610 
3611  if (glSemantic != null)
3612  {
3613  glSemantic = ResolveSemantic(semantic, type, isInput, varName, out defaultType, out semanticIndex, span);
3614  }
3615  else
3616  {
3617  span = type.Span;
3618  }
3619 
3620  string variableName = glSemantic == null ? varName : glSemantic.Name.Text;
3621 
3622  bool addGlslGlobalVariable = string.Compare(variableName, "gl_Position", StringComparison.InvariantCultureIgnoreCase) == 0 && defaultType != type;
3623 
3624  if (variableName.StartsWith("gl_fragdata", StringComparison.InvariantCultureIgnoreCase) && isPixelShaderOutputFragDataMuliType)
3625  {
3626  // IF varName is null, this is a semantic from a returned function, so use a generic out_gl_fragdata name
3627  // otherwise, use the original variable name.
3628  variableName = varName != null ? "out_gl_fragdata_" + varName : "out_gl_fragdata";
3629  addGlslGlobalVariable = true;
3630  }
3631 
3632  // var firstContext = DeclarationContexts.First();
3633  var variable = FindDeclaration(variableName) as Variable;
3634  if (variable == null)
3635  {
3636  variable = new Variable(defaultType, variableName) { Span = span };
3637 
3638  if (addGlslGlobalVariable)
3639  {
3640  variable.Type = type;
3641  if (isInput)
3642  {
3643  variable.Qualifiers |= Ast.ParameterQualifier.In;
3644  }
3645  else
3646  {
3647  variable.Qualifiers |= Ast.ParameterQualifier.Out;
3648  }
3649  }
3650 
3651  AddGlobalDeclaration(variable, addGlslGlobalVariable);
3652  }
3653 
3654  return variable;
3655  }
3656 
3657  /// <summary>
3658  /// Gets the variable tag.
3659  /// </summary>
3660  /// <param name="node">The variable.</param>
3661  /// <param name="alias">The alias name (semantic or register).</param>
3662  /// <returns>
3663  /// The tag associated with a variable
3664  /// </returns>
3665  private TagLayout GetTagLayout(Node node, string alias = null)
3666  {
3667  var variable = node as Variable;
3668  var constantBuffer = node as ConstantBuffer;
3669 
3670  var layoutTag = node.GetTag(TagLayoutKey) as TagLayout;
3671  if (layoutTag == null)
3672  {
3673  layoutTag = new TagLayout();
3674  node.SetTag(TagLayoutKey, layoutTag);
3675 
3676  if (variable != null)
3677  {
3678  MapRule mapType;
3679  if (MapRules.TryGetValue(variable.Name, out mapType))
3680  {
3681  layoutTag.Type = mapType.Type;
3682  }
3683  }
3684 
3685  // Only for vertex shader input
3686  if (alias != null)
3687  {
3688  if (variable != null)
3689  {
3690  var variableLayoutRule = this.FindVariableLayoutBySemantic(alias);
3691  if (variableLayoutRule != null)
3692  {
3693  // Update location from external layout
3694  if (variableLayoutRule.Location != null)
3695  {
3696  int locationIndex;
3697  if (int.TryParse(variableLayoutRule.Location, out locationIndex))
3698  {
3699  layoutTag.Location = locationIndex;
3700  }
3701  else
3702  {
3703  layoutTag.Location = variableLayoutRule.Location;
3704  }
3705  }
3706 
3707  // Use output or input name
3708  layoutTag.Name = variable.Qualifiers.Contains(Ast.ParameterQualifier.Out) ? variableLayoutRule.NameOutput : variableLayoutRule.Name;
3709  }
3710  }
3711  else if (constantBuffer != null)
3712  {
3713  var cBufferLayoutRule = this.FindConstantBufferLayoutByRegister(alias);
3714  if (cBufferLayoutRule != null)
3715  {
3716  if (cBufferLayoutRule.Binding != null)
3717  {
3718  int bindingIndex;
3719  if (int.TryParse(cBufferLayoutRule.Binding, out bindingIndex))
3720  {
3721  layoutTag.Binding = bindingIndex;
3722  }
3723  else
3724  {
3725  layoutTag.Binding = cBufferLayoutRule.Binding;
3726  }
3727  }
3728  }
3729  }
3730  }
3731 
3732  if (variable != null)
3733  {
3734 
3735  }
3736 
3737  if (variable != null && layoutTag.Name == null)
3738  layoutTag.Name = variable.Name.Text;
3739 
3740  layoutTag.Qualifier = new Ast.Glsl.LayoutQualifier();
3741  }
3742 
3743  return layoutTag;
3744  }
3745 
3746  /// <summary>
3747  /// Rebinds all VariableReferenceExpression to the final name.
3748  /// </summary>
3749  private void RebindVariableReferenceExpressions()
3750  {
3751  SearchVisitor.Run(
3752  shader,
3753  node =>
3754  {
3755  if (node is VariableReferenceExpression)
3756  {
3757  var variableRef = (VariableReferenceExpression)node;
3758  if (variableRef.TypeInference.Declaration is Variable)
3759  variableRef.Name = variableRef.TypeInference.Declaration.Name;
3760  }
3761  else if (node is MethodInvocationExpression)
3762  {
3763  var methodRef = (MethodInvocationExpression)node;
3764  var variableRef = methodRef.Target as VariableReferenceExpression;
3765  var methodDeclaration = variableRef != null ? variableRef.TypeInference.Declaration as MethodDeclaration : null;
3766  if (variableRef != null && methodDeclaration != null && !methodDeclaration.IsBuiltin)
3767  variableRef.Name = methodDeclaration.Name;
3768  }
3769 
3770  return node;
3771  });
3772  }
3773 
3774  /// <summary>
3775  /// Removes the default parameters for methods.
3776  /// </summary>
3777  private void RemoveDefaultParametersForMethods()
3778  {
3779  SearchVisitor.Run(
3780  shader,
3781  node =>
3782  {
3783  var declaration = node as Parameter;
3784  if (declaration != null && declaration.InitialValue != null)
3785  declaration.InitialValue = null;
3786  return node;
3787  });
3788  }
3789 
3790  private static string RenameGlslKeyword(string name)
3791  {
3792  if (GlslKeywords.IsReserved(name))
3793  name = "_" + name + "_";
3794 
3795  // Replace all variable using __ with _t_
3796  return name.Replace("__", "_t_");
3797  }
3798 
3799  /// <summary>
3800  /// If requested, Z projection coordinates will be remapped from [0;1] to [-1;1] at end of vertex shader.
3801  /// </summary>
3802  private void RemapCoordinates(StatementList list)
3803  {
3804  if (ViewFrustumRemap && pipelineStage == PipelineStage.Vertex && entryPoint is MethodDefinition)
3805  {
3806  // Add gl_Position.z = gl_Position.z * 2.0f - gl_Position.w
3807  list.Add(
3808  new ExpressionStatement(
3809  new AssignmentExpression(
3810  AssignmentOperator.Default,
3811  new MemberReferenceExpression(new VariableReferenceExpression("gl_Position"), "z"),
3812  new BinaryExpression(
3813  BinaryOperator.Minus,
3814  new BinaryExpression(
3815  BinaryOperator.Multiply,
3816  new MemberReferenceExpression(new VariableReferenceExpression("gl_Position"), "z"),
3817  new LiteralExpression(2.0f)),
3818  new MemberReferenceExpression(new VariableReferenceExpression("gl_Position"), "w"))
3819  )));
3820  list.Add(
3821  new ExpressionStatement(
3822  new AssignmentExpression(
3823  AssignmentOperator.Default,
3824  new MemberReferenceExpression(new VariableReferenceExpression("gl_Position"), "y"),
3825  new BinaryExpression(
3826  BinaryOperator.Multiply,
3827  new VariableReferenceExpression("ParadoxFlipRendertarget"),
3828  new MemberReferenceExpression(new VariableReferenceExpression("gl_Position"), "y"))
3829  )));
3830  }
3831  }
3832 
3833  /// <summary>
3834  /// Renames all declaration that are using a GLSL keywords.
3835  /// </summary>
3836  private void RenameGlslKeywords()
3837  {
3838  SearchVisitor.Run(
3839  shader,
3840  node =>
3841  {
3842  var declaration = node as IDeclaration;
3843  var variableRef = node as VariableReferenceExpression;
3844  if (declaration != null && declaration.Name != null)
3845  {
3846  if (!(declaration is Variable && ((Variable)declaration).Type.Name.Text.StartsWith("layout")))
3847  {
3848  declaration.Name.Text = RenameGlslKeyword(declaration.Name.Text);
3849  }
3850  }
3851  else if (variableRef != null)
3852  {
3853  variableRef.Name.Text = RenameGlslKeyword(variableRef.Name.Text);
3854  }
3855 
3856  return node;
3857  });
3858  }
3859 
3860  private KeyValuePair<string, int> GetGlVariableFromSemantic(Semantic rawSemantic, bool isInput, out string semanticGl, out string semanticGlBase, out int semanticIndex)
3861  {
3862  var semanticName = rawSemantic.Name.Text;
3863  var semantic = ParseSemantic(semanticName);
3864 
3865  Dictionary<string, string> semanticMapping = null;
3866  switch (pipelineStage)
3867  {
3868  case PipelineStage.Vertex:
3869  semanticMapping = isInput ? builtinVertexInputs : builtinVertexOutputs;
3870  break;
3871  case PipelineStage.Geometry:
3872  semanticMapping = isInput ? builtinGeometryInputs : builtinGeometryOutputs;
3873  break;
3874  case PipelineStage.Pixel:
3875  semanticMapping = isInput ? builtinPixelInputs : builtinPixelOutputs;
3876  break;
3877  }
3878 
3879  semanticGl = null;
3880 
3881  if (semanticMapping != null && !semanticMapping.TryGetValue(semanticName, out semanticGl))
3882  semanticMapping.TryGetValue(semantic.Key, out semanticGl);
3883 
3884  // Special case for point sprite
3885  if (semanticName != null && semanticName.Equals("TEXCOORD0") && IsPointSpriteShader && pipelineStage == PipelineStage.Pixel)
3886  semanticGl = "gl_PointCoord";
3887 
3888  // Set the semantic gl base name
3889  semanticGlBase = semanticGl;
3890  semanticIndex = semantic.Value;
3891 
3892  if (semanticGl != null && semanticGl.EndsWith("[]"))
3893  {
3894  semanticGlBase = semanticGl.Substring(0, semanticGl.Length - 2);
3895 
3896  // If there is [] at the end of the string, insert semantic index within []
3897  semanticGl = semanticGlBase + "[" + semantic.Value + "]";
3898  }
3899 
3900  return semantic;
3901  }
3902 
3903  private string GetGlVariableNameFromSemantic(Semantic rawSemantic, bool isInput)
3904  {
3905  string semanticGlBase = null;
3906  string semanticGl = null;
3907  int semanticIndex;
3908  GetGlVariableFromSemantic(rawSemantic, isInput, out semanticGl, out semanticGlBase, out semanticIndex);
3909 
3910  return semanticGl;
3911  }
3912 
3913  /// <summary>
3914  /// Resolves the HLSL semantic into GLSL one for a given uniform.
3915  /// It will also adds the varying to the GLSL shader the first time it is found.
3916  /// </summary>
3917  /// <param name="rawSemantic">The raw semantic.</param>
3918  /// <param name="type">The type.</param>
3919  /// <param name="isInput">if set to <c>true</c> input, otherwise output.</param>
3920  /// <param name="varName">Name of the var.</param>
3921  /// <returns>A semantic transformed</returns>
3922  private Semantic ResolveSemantic(Semantic rawSemantic, TypeBase type, bool isInput, string varName, out TypeBase glslType, out int semanticIndex, SourceSpan span)
3923  {
3924  string semanticGlBase = null;
3925  string semanticGl = null;
3926  var semantic = GetGlVariableFromSemantic(rawSemantic, isInput, out semanticGl, out semanticGlBase, out semanticIndex);
3927 
3928  if (semanticGl == null)
3929  {
3930  // Prefix with a_ or v_ ( attribute or varying )
3931  if (isInput && (pipelineStage == PipelineStage.Vertex))
3932  semanticGl = "a_" + (this.UseSemanticForVariable ? semantic.Key + semantic.Value : varName);
3933  else if ((isInput == false) && (pipelineStage == PipelineStage.Pixel))
3934  semanticGl = "vout_" + (this.UseSemanticForVariable ? semantic.Key + semantic.Value : varName);
3935  else
3936  semanticGl = "v_" + (this.UseSemanticForVariable ? semantic.Key + semantic.Value : varName);
3937 
3938  var variable = FindDeclaration(semanticGl) as Variable;
3939  if (variable == null)
3940  {
3941  variable = new Variable(type, semanticGl) { Span = span };
3942  variable.Qualifiers |= isInput ? Ast.ParameterQualifier.In : Ast.ParameterQualifier.Out;
3943 
3944  // Setup Variable Tag for LayoutQualifiers
3945  //GetTagLayout(variable, semanticName, isInput && pipelineStage == PipelineStage.Vertex);
3946  this.GetTagLayout(variable, rawSemantic.Name.Text);
3947 
3948  AddGlobalDeclaration(variable);
3949  }
3950  glslType = type;
3951  }
3952  else
3953  {
3954  if (builtinGlslTypes.TryGetValue(semanticGlBase, out glslType))
3955  {
3956  // If type is an array type, create the equivalent arrayType
3957  var arrayType = type as ArrayType;
3958  if (arrayType != null)
3959  glslType = new ArrayType(glslType, arrayType.Dimensions.ToArray());
3960  }
3961  else
3962  {
3963  parserResult.Warning("No default type defined for glsl semantic [{0}]. Use [{1}] implicit type instead.", rawSemantic.Span, semanticGlBase, type);
3964  glslType = type;
3965  }
3966  }
3967 
3968  return new Semantic(semanticGl);
3969  }
3970 
3971  /// <summary>
3972  /// Tranforms to GLSL types.
3973  /// </summary>
3974  private void TranformToGlslTypes()
3975  {
3976  var mapToGlsl = new Dictionary<TypeBase, TypeBase>();
3977 
3978  // Add vector type conversion
3979  foreach (var type in new[] { ScalarType.Bool, ScalarType.Int, ScalarType.UInt, ScalarType.Float, ScalarType.Double, ScalarType.Half })
3980  {
3981  var targetSubType = type == ScalarType.Half ? ScalarType.Float : type;
3982  var prefix = CalculateGlslPrefix(type);
3983 
3984  for (int i = 2; i <= 4; ++i)
3985  mapToGlsl.Add(new VectorType(type, i), new TypeName(prefix + "vec" + i));
3986 
3987  // Half are converted to float
3988  mapToGlsl.Add(new VectorType(type, 1), targetSubType);
3989  }
3990 
3991  // Add matrix type conversion
3992  foreach (var type in new[] { ScalarType.Double, ScalarType.Float, ScalarType.Half })
3993  {
3994  var prefix = CalculateGlslPrefix(type);
3995  for (int i = 2; i <= 4; ++i)
3996  {
3997  for (int j = 2; j <= 4; ++j)
3998  {
3999  // Swap column/matrix if NoSwapForBinaryMatrixOperation is true
4000  int column = NoSwapForBinaryMatrixOperation ? j : i;
4001  int row = NoSwapForBinaryMatrixOperation ? i : j;
4002 
4003  string matrixName = i == j ? string.Format(prefix + "mat{0}", i) : string.Format(prefix + "mat{0}x{1}", column, row);
4004 
4005  mapToGlsl.Add(new MatrixType(type, i, j), new TypeName(matrixName));
4006  }
4007  }
4008  }
4009 
4010  mapToGlsl.Add(ScalarType.Half, ScalarType.Float);
4011  mapToGlsl.Add(new MatrixType(ScalarType.Float, 1, 1), ScalarType.Float);
4012 
4013  // Sampler objects
4014  mapToGlsl.Add(SamplerType.Sampler, SamplerType.Sampler2D);
4015  mapToGlsl.Add(SamplerType.SamplerCube, new TypeName("samplerCube"));
4016 
4017  // Replace all generic shader types to their glsl equivalent.
4018  SearchVisitor.Run(
4019  shader,
4020  node =>
4021  {
4022  if (node is TypeBase && !(node is Typedef) && !(node is ArrayType))
4023  {
4024  var type = (TypeBase)node;
4025  var targetType = type.ResolveType();
4026  TypeBase outputType;
4027  if (mapToGlsl.TryGetValue(targetType, out outputType))
4028  return outputType;
4029  }
4030 
4031  return node;
4032  });
4033  }
4034 
4035  /// <summary>
4036  /// Transforms all variable declared with a multidimensional array to a single dimension.
4037  /// </summary>
4038  private void TransformArrayDimensions()
4039  {
4040  foreach (var variable in listOfMultidimensionArrayVariable)
4041  {
4042  Expression newSubscript = null;
4043 
4044  var arrayType = (ArrayType)variable.Type.ResolveType();
4045  var arrayElementType = arrayType.Type.ResolveType();
4046 
4047  // float myarray[i1][i2][i3]...[in] => float myarray[(i1)*(i2)*(i3)*...*(in)]
4048  foreach (var subscript in arrayType.Dimensions)
4049  newSubscript = newSubscript == null ? subscript : new BinaryExpression(BinaryOperator.Multiply, newSubscript, subscript);
4050 
4051  // Set the new subscript
4052  var newArrayType = new ArrayType { Type = new TypeName(arrayElementType) };
4053  newArrayType.Dimensions.Add(newSubscript);
4054  variable.Type = newArrayType;
4055  }
4056 
4057  // For arrays with dynamic dimension, we need to replace it with the actual number of initializers
4058  foreach (var variable in shader.Declarations.OfType<Variable>())
4059  {
4060  var variableArrayType = variable.Type.ResolveType() as ArrayType;
4061  if (variableArrayType != null)
4062  {
4063  if (variable.InitialValue != null)
4064  {
4065  var arrayInitializers = variable.InitialValue as MethodInvocationExpression;
4066  if (arrayInitializers != null && variableArrayType.Dimensions.Count == 1)
4067  {
4068  var currentDimension = variableArrayType.Dimensions[0] as LiteralExpression;
4069  if (currentDimension != null)
4070  {
4071  int currentDim = Convert.ToInt32(currentDimension.Literal.Value);
4072  if (currentDim < arrayInitializers.Arguments.Count)
4073  {
4074  variableArrayType.Dimensions.Clear();
4075  variableArrayType.Dimensions.Add(new LiteralExpression(arrayInitializers.Arguments.Count));
4076  }
4077  }
4078  }
4079  }
4080  }
4081  }
4082  }
4083 
4084  /// <summary>
4085  /// Converts an HLSL array initializer to a GLSL array initializer.
4086  /// Example:
4087  /// HLSL float[4] test = {1,2,3,4};
4088  /// GLSL float[4] test = float[](1,2,3,4);
4089  /// </summary>
4090  /// <param name="arrayType">Type of the array.</param>
4091  /// <param name="arrayInitializer">The array initializer.</param>
4092  /// <returns>A converted array</returns>
4093  private Expression ConvertArrayInitializer(ArrayType arrayType, ArrayInitializerExpression arrayInitializer)
4094  {
4095  var arrayElementType = arrayType.Type.ResolveType();
4096 
4097  var newArrayExpression = new MethodInvocationExpression(new IndexerExpression(new TypeReferenceExpression(arrayType.Type), new LiteralExpression()));
4098  var arrayItems = new List<Expression>();
4099  FlattenArrayCreationExpression(arrayInitializer, arrayItems);
4100 
4101  // By default add array
4102  newArrayExpression.Arguments.AddRange(arrayItems);
4103 
4104  // Convert array/vector initializer
4105  // vec4 value[4] = vec4[4](0,0,0,0, 0,0,0,0, 0,0,0,0); to => vec4 value[4] = vec4[4](vec4(0,0,0,0), vec4(0,0,0,0), vec4(0,0,0,0));
4106  var vectorType = arrayElementType as VectorType;
4107  if (vectorType != null)
4108  {
4109  // If there is exactly the same number of arguments and all arguments are primitives, then convert
4110  if ((arrayItems.Count % vectorType.Dimension) == 0 && arrayItems.All(arg => (arg.TypeInference.TargetType is ScalarType)))
4111  {
4112  var arguments = new List<Expression>();
4113  var vectorArgs = new List<Expression>();
4114  foreach (var arg in arrayItems)
4115  {
4116  vectorArgs.Add(arg);
4117  if (vectorArgs.Count == vectorType.Dimension)
4118  {
4119  arguments.Add(new MethodInvocationExpression(new TypeReferenceExpression(vectorType), vectorArgs.ToArray()));
4120  vectorArgs.Clear();
4121  }
4122  }
4123 
4124  newArrayExpression.Arguments = arguments;
4125  }
4126  }
4127 
4128  if (arrayType.IsDimensionEmpty)
4129  {
4130  arrayType.Dimensions.Clear();
4131  arrayType.Dimensions.Add(new LiteralExpression(newArrayExpression.Arguments.Count));
4132  }
4133 
4134  return newArrayExpression;
4135  }
4136 
4137  /// <summary>
4138  /// Converts an HLSL matrix initializer to a GLSL matrix initializer.
4139  /// </summary>
4140  /// <param name="matrixType">Type of the matrix.</param>
4141  /// <param name="initializers">The initializers.</param>
4142  /// <returns>
4143  /// A converted matrix
4144  /// </returns>
4145  private List<Expression> ConvertMatrixInitializer(MatrixType matrixType, List<Expression> initializers)
4146  {
4147  if (!NoSwapForBinaryMatrixOperation)
4148  return initializers;
4149 
4150  var newInitializers = new List<Expression>();
4151 
4152  int columnCount = matrixType.ColumnCount;
4153  int rowCount = matrixType.RowCount;
4154 
4155  // Initializers could be
4156  // 1) matrix test = matrix( float4(row1), float4(row2), float4(row3), float4(row4) );
4157  // or
4158  // 2) matrix test = matrix( 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
4159  if (rowCount == initializers.Count)
4160  {
4161  // Case 1)
4162  // We need to transpose rows into columns
4163  for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
4164  {
4165  var columnInitializerType = new VectorType((ScalarType)matrixType.Type.ResolveType(), rowCount);
4166  var columnInitializer = new MethodInvocationExpression(new TypeReferenceExpression(columnInitializerType));
4167  newInitializers.Add(columnInitializer);
4168 
4169  for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
4170  {
4171  var elementIndexer = new IndexerExpression(initializers[rowIndex], new LiteralExpression(columnIndex));
4172  columnInitializer.Arguments.Add(elementIndexer);
4173  }
4174  }
4175  }
4176  else if ((rowCount * columnCount) == initializers.Count)
4177  {
4178  // Case 2)
4179  // We need to transpose all the elements
4180  for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
4181  {
4182  for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
4183  {
4184  newInitializers.Add(initializers[rowCount * rowIndex + columnIndex]);
4185  }
4186  }
4187  }
4188  else
4189  {
4190  newInitializers = initializers;
4191  parserResult.Warning("Unable to convert matrix initializer [{0}] to matrix type [{1}]", matrixType.Span, string.Join(",", initializers), matrixType);
4192  }
4193 
4194  return newInitializers;
4195  }
4196 
4197  /// <summary>
4198  /// Transforms the global multiple variable to single variable.
4199  /// </summary>
4200  private void TransformGlobalMultipleVariableToSingleVariable()
4201  {
4202  var declarations = new List<Node>();
4203 
4204  foreach (var declaration in shader.Declarations)
4205  {
4206  var variable = declaration as Variable;
4207  if (variable != null && variable.IsGroup)
4208  {
4209  foreach (var subVariable in variable.SubVariables)
4210  {
4211  // Copy Qualifiers
4212  subVariable.Qualifiers = Qualifier.None;
4213  subVariable.Qualifiers |= variable.Qualifiers;
4214  declarations.Add(subVariable);
4215  }
4216  }
4217  else
4218  declarations.Add(declaration);
4219  }
4220 
4221  shader.Declarations = declarations;
4222  }
4223 
4224 
4225  private static List<StructMemberReference> GetMembers(StructType structType, List<StructMemberReference> members = null, List<Variable> fieldStack = null )
4226  {
4227  // Cache the members if they have been already calculated for a particular type
4228  // Though, this is not realy efficient (should cache nested struct member reference...)
4229  if (members == null)
4230  {
4231  members = (List<StructMemberReference>)structType.GetTag("Members");
4232  if (members != null)
4233  return members;
4234 
4235  members = new List<StructMemberReference>();
4236  structType.SetTag("Members", members);
4237  }
4238 
4239  if (fieldStack == null)
4240  fieldStack = new List<Variable>();
4241 
4242  // Iterate on all fields to build the member references
4243  foreach (var field in structType.Fields.SelectMany(item => item.Instances()))
4244  {
4245  var fieldType = field.Type.ResolveType();
4246 
4247  // This is a "recursive" struct type
4248  if (fieldType is StructType)
4249  {
4250  fieldStack.Add(field);
4251  GetMembers((StructType)fieldType, members, fieldStack);
4252  fieldStack.RemoveAt(fieldStack.Count - 1);
4253  }
4254  else
4255  {
4256  var structMember = new StructMemberReference();
4257  structMember.Field = field;
4258  structMember.ParentFields.AddRange(fieldStack);
4259 
4260  var fieldPath = new StringBuilder();
4261  bool isFirst = true;
4262  foreach(var parentField in Enumerable.Reverse(fieldStack))
4263  {
4264  if (!isFirst)
4265  fieldPath.Append("_");
4266  fieldPath.Append(parentField.Name);
4267  isFirst = false;
4268  }
4269 
4270  if (fieldPath.Length > 0)
4271  fieldPath.Append("_");
4272  fieldPath.Append(field.Name);
4273 
4274  structMember.FieldNamePath = fieldPath.ToString();
4275  members.Add(structMember);
4276  }
4277  }
4278 
4279  return members;
4280  }
4281 
4282  private static Expression NewCast(TypeBase type, params Expression[] expressions)
4283  {
4284  return new MethodInvocationExpression(new TypeReferenceExpression(type), expressions);
4285  }
4286 
4287  private class StructMemberReference
4288  {
4289  public string FieldNamePath;
4290 
4291  public MemberReferenceExpression GetMemberReference(Expression target)
4292  {
4293  var currentMemberRef = new MemberReferenceExpression(target, Field.Name);
4294 
4295  foreach (var parentField in Enumerable.Reverse(ParentFields))
4296  {
4297  currentMemberRef.Target = new MemberReferenceExpression(currentMemberRef.Target, parentField.Name);
4298  }
4299  return currentMemberRef;
4300  }
4301 
4302  public List<Variable> ParentFields = new List<Variable>();
4303 
4304  public Variable Field;
4305  }
4306 
4307  class SemanticReference
4308  {
4309  public SemanticReference(string name, Expression variableReference)
4310  {
4311  this.Name = name;
4312  this.VariableReference = variableReference;
4313  }
4314 
4315  public string Name;
4316 
4317  public Expression VariableReference;
4318  }
4319 
4320  #endregion
4321 
4322  /// <summary>
4323  /// A Tag associated to a variable
4324  /// </summary>
4325  private class TagLayout
4326  {
4327  #region Constants and Fields
4328 
4329  public object Binding { get; set; }
4330 
4331  public object Location { get; set; }
4332 
4333  public string Name;
4334 
4335  public string Type;
4336 
4337  public Ast.Glsl.LayoutQualifier Qualifier;
4338 
4339  #endregion
4340  }
4341  }
4342 }
Base class for all vector types
Definition: VectorType.cs:10
SiliconStudio.Shaders.Ast.Hlsl.ConstantBuffer ConstantBuffer
static readonly ScalarType Bool
Scalar bool.
Definition: ScalarType.cs:17
TypeBase TargetType
Gets or sets the type.
Identifier Name
Gets or sets the name.
Definition: Variable.cs:77
Statement VisitStatementAsMemberInvocation(Statement statement, MethodInvocationExpression methodInvocationExpression, MemberReferenceExpression memberReferenceExpression)
Visits a statement that is a member invocation.
TypeBase Type
Gets or sets the type.
Definition: Variable.cs:61
Describes a binary expression.
static readonly ScalarType Int
Scalar int.
Definition: ScalarType.cs:37
UnaryOperator
Unary operator used in all binary expressions (except assignment expression).
A typeless reference.
Definition: TypeName.cs:10
Technique Visit(Technique technique)
Visits the specified technique.
List< Statement > Statements
Gets or sets the statements.
List< Expression > Items
Gets or sets the items.
TypeInference TypeInference
Gets or sets the resolved reference.
Definition: TypeBase.cs:69
Statement Visit(Statement statement)
Visits the specified statement.
Expression Visit(ArrayInitializerExpression arrayCreationExpression)
Visits the specified array creation expression.
void PostVisitEntryPoint(MethodDefinition function)
Visits the entry point.
Expression Visit(BinaryExpression binaryExpression)
Visits the specified binary expression.
SourceSpan Span
Gets or sets the source span.
Definition: Node.cs:37
Keyword expression statement like continue; break; discard;
ShaderModel
Describes a HLSL ShaderModel (SM2, SM3, SM4...etc.)
Definition: ShaderModel.cs:10
string Text
Gets or sets the name.
Definition: Identifier.cs:77
SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier LayoutQualifier
static readonly TextureType Texture2D
A Texture2D
Definition: TextureType.cs:36
Qualifier Qualifiers
Gets or sets the qualifiers.
Definition: Variable.cs:53
Statement VisitStatementAsFunctionInvocation(Statement statement, MethodInvocationExpression methodInvocationExpression, VariableReferenceExpression methodVar)
Visits a statement that is a function invocation.
Expression used to initliaze an array {...expressions,}
void Visit(IfStatement ifStatement)
Visits the specified if statement.
TypeBase Type
Gets or sets the type.
Definition: MatrixType.cs:91
static readonly TextureType TextureCube
An TextureCube.
Definition: TextureType.cs:51
BinaryOperator
Binary operator used in all binary expressions (except assignment expression).
Node Visit(Variable variable)
Visits the specified variable.
void Visit(Shader shader)
Visits the specified shader.
static readonly TextureType Texture3D
A Texture3D.
Definition: TextureType.cs:46
virtual TypeBase ResolveType()
Resolves the type.
Definition: TypeBase.cs:101
Expression Target
Gets or sets the target receving the assigment.
bool IsDimensionEmpty
Gets a value indicating whether this instance is dimension empty.
Definition: ArrayType.cs:77
AssignmentOperator
Assignment operator used in assignment expression (a = b) or statements (a = b;)
int ColumnCount
Gets or sets the column count.
Definition: MatrixType.cs:53
static readonly VectorType Float4
A Float4
Definition: VectorType.cs:57
An expression surrounded by parenthesis.
A method definition with a body of statements.
static readonly ScalarType Half
Scalar half.
Definition: ScalarType.cs:32
Expression Visit(MemberReferenceExpression expression)
Visits the specified expression.
Abstract node.
Definition: Node.cs:15
static readonly VectorType Int4
A Int4
Definition: VectorType.cs:27
static readonly ScalarType UInt
Scalar unsigned int.
Definition: ScalarType.cs:42
TypeInference TypeInference
Gets or sets the type reference.
Definition: Expression.cs:28
static readonly ScalarType Float
Sclar float.
Definition: ScalarType.cs:27
Expression Value
Gets or sets the value of the assigment..
_In_ size_t count
Definition: DirectXTexP.h:174
void Run(ParsingResult parserResultIn)
Runs the convertor on the specified parser result.
static readonly TextureType Texture1D
A Texture1D.
Definition: TextureType.cs:26
Statement Visit(StatementList statementList)
Visits the specified statement list.
A variable declaration.
Definition: Variable.cs:11
Base root class for all statements.
Definition: Statement.cs:11
A single parameter declaration.
Definition: Parameter.cs:10
Describes a packoffset(value).
Definition: PackOffset.cs:13
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
List< Expression > Arguments
Gets or sets the arguments.
void Visit(MethodDefinition function)
Visits the specified function.
SiliconStudio.Paradox.Games.Mathematics.Half Half
static TypeBase GetBaseType(TypeBase type)
Definition: TypeBase.cs:127
A member reference in the form {this}.{Name}
The strip visitor collects all function and declaration used by a set of entrypoints and remove any u...
Definition: StripVisitor.cs:15
Expression Visit(IndexerExpression indexerExpression)
Visits the specified indexer expression.
Expression Visit(ConditionalExpression conditionalExpression)
Visits the specified conditional expression.
HRESULT Convert(_In_ const Image &srcImage, _In_ DXGI_FORMAT format, _In_ DWORD filter, _In_ float threshold, _Out_ ScratchImage &image)
static void Prepare(Shader shader)
Prepares the specified shader for glsl to hlsl conversion (before type inference analysis).
Base type for all types.
Definition: TypeBase.cs:11
static bool IsStreamType(TypeBase targetType)
Determines whether the specified type is a a stream type.
Expression Visit(MethodInvocationExpression methodInvocationExpression)
Visits the specified method invocation expression.
Node Visit(ForStatement forStatement)
Visit the for statement and unroll it if necessary
SiliconStudio.Shaders.Ast.SourceSpan SourceSpan
Definition: Node.cs:8
Expression Visit(CastExpression castExpression)
Visits the specified cast expression.
static readonly ScalarType Double
Scalar double.
Definition: ScalarType.cs:22
SiliconStudio.Shaders.Ast.StorageQualifier StorageQualifier
Declaration of a constant buffer.
void PrepareVisitEntryPoint(MethodDefinition function)
Prepares the visit of entry point.
Toplevel container of a shader parsing result.
Definition: Shader.cs:12
bool Contains(CompositeEnum enumValue)
Determines whether [contains] [the specified enum value].
List< Parameter > Parameters
Gets or sets the parameters.
Collect a list of global uniforms that are used as global temporary variable.
char * dest
Definition: lz4.h:61
static readonly VectorType Int2
A Int2
Definition: VectorType.cs:17
TypeBase Type
Gets or sets the type.
Definition: ArrayType.cs:68
OrderedSet< CompositeEnum > Values
Gets or sets the values.
Toplevel interface for a declaration.
Definition: IDeclaration.cs:8
Statement VisitStatementAsAssignExpression(Statement statement, AssignmentExpression assignmentExpression)
HlslToGlslConvertor(string entryPointName, PipelineStage pipelineStage, ShaderModel shaderModel, bool useBuiltinSemantic=true)
Initializes a new instance of the HlslToGlslConvertor class.
Expression Visit(AssignmentExpression assignExpression)
Visits the specified assign expression.
SiliconStudio.Shaders.Ast.ParameterQualifier ParameterQualifier
Statement Visit(ReturnStatement returnStatement)
Visits the specified return statement.
Identifier Name
Gets or sets the type name.
Definition: TypeBase.cs:77
Expression Visit(VariableReferenceExpression varRefExpr)
Visits the specified var ref expr.
Collect the texture and sampler pair used in the HLSL shader.
virtual Expression Visit(ParenthesizedExpression parenthesizedExpression)
Visits the specified parenthesized expression.
List< Variable > Fields
Gets or sets the fields.
Definition: StructType.cs:34
HLSL to GLSL conversion requires several steps:
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
PipelineStage
Enum to specify pipeline stage.
void Visit(ConstantBuffer constantBuffer)
Visits the specified constant buffer.
object GetTag(object tagKey)
Gets a tag value associated to this node..
Definition: Node.cs:78
Specialized ParameterQualifier for Hlsl.
static bool IsInteger(TypeBase type)
Determines whether the specified type is an integer.
Definition: ScalarType.cs:180