/// <summary> /// Initializes a new instance of the <see cref="ShaderConverter"/> class. /// </summary> public ShaderConverter(GlslShaderPlatform shaderPlatform, int shaderVersion) { this.shaderPlatform = shaderPlatform; this.shaderVersion = shaderVersion; IsVerboseLog = true; Macros = new List <ShaderMacro>(); }
/// <summary> /// Initializes a new instance of the <see cref="ShaderConverter"/> class. /// </summary> public ShaderConverter(GlslShaderPlatform shaderPlatform, int shaderVersion) { this.shaderPlatform = shaderPlatform; this.shaderVersion = shaderVersion; IsVerboseLog = true; Macros = new List<ShaderMacro>(); }
/// <summary> /// Initializes a new instance of the <see cref="HlslWriter"/> class. /// </summary> /// <param name="useNodeStack"> /// if set to <c>true</c> [use node stack]. /// </param> public HlslToGlslWriter(GlslShaderPlatform shaderPlatform, int shaderVersion, PipelineStage pipelineStage, bool useNodeStack = false) : base(useNodeStack) { this.shaderPlatform = shaderPlatform; this.shaderVersion = shaderVersion; this.pipelineStage = pipelineStage; if (shaderPlatform == GlslShaderPlatform.OpenGLES) { TrimFloatSuffix = true; GenerateUniformBlocks = shaderVersion >= 300; SupportsTextureBuffer = shaderVersion >= 320; } }
private string RunOptimizer(ShaderBytecodeResult shaderBytecodeResult, string baseShader, GlslShaderPlatform shaderPlatform, int shaderVersion, bool vertex) { lock (GlslOptimizerLock) { IntPtr ctx = IntPtr.Zero; var inputShader = baseShader; if (shaderPlatform == GlslShaderPlatform.OpenGLES) { if (shaderVersion >= 300) { ctx = glslopt_initialize(2); // kGlslTargetOpenGLES30 } else { ctx = glslopt_initialize(1); // kGlslTargetOpenGLES20 } } else { ctx = glslopt_initialize(0); // kGlslTargetOpenGL } int type = vertex ? 0 : 1; var shader = glslopt_optimize(ctx, type, inputShader, 0); bool optimizeOk = glslopt_get_status(shader); string shaderAsString = null; if (optimizeOk) { IntPtr optShader = glslopt_get_output(shader); shaderAsString = Marshal.PtrToStringAnsi(optShader); } else { IntPtr log = glslopt_get_log(shader); var logAsString = Marshal.PtrToStringAnsi(log); shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n glsl_opt: {0}", string.Join("\r\n glsl_opt: ", logAsString.Split(new[] { "\n", "\r", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))); } glslopt_shader_delete(shader); glslopt_cleanup(ctx); return(shaderAsString); } }
private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, string sourceFilename = null) { if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && renderTargetCount > 1) { shaderBytecodeResult.Error("OpenGL ES 2 does not support multiple render targets."); } PipelineStage pipelineStage = PipelineStage.None; switch (stage) { case ShaderStage.Vertex: pipelineStage = PipelineStage.Vertex; break; case ShaderStage.Pixel: pipelineStage = PipelineStage.Pixel; break; case ShaderStage.Geometry: shaderBytecodeResult.Error("Geometry stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Hull: shaderBytecodeResult.Error("Hull stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Domain: shaderBytecodeResult.Error("Domain stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Compute: shaderBytecodeResult.Error("Compute stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; default: shaderBytecodeResult.Error("Unknown shader profile."); break; } if (shaderBytecodeResult.HasErrors) { return(null); } Shader glslShader; // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter // TODO: support that directly in HlslToGlslConvertor? if (entryPoint == null) { glslShader = null; } else { // Convert from HLSL to GLSL // Note that for now we parse from shader as a string, but we could simply clone effectPass.Shader to avoid multiple parsing. var glslConvertor = new ShaderConverter(shaderPlatform, shaderVersion); glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult); if (glslShader == null || shaderBytecodeResult.HasErrors) { return(null); } foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>()) { // Update constant buffer itself (first time only) var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0); if (reflectionConstantBuffer != null) { // Used to compute constant buffer size and member offsets (std140 rule) int constantBufferOffset = 0; // Fill members for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++) { var member = reflectionConstantBuffer.Members[index]; // Properly compute size and offset according to std140 rules var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset); // Store size/offset info member.Offset = constantBufferOffset; member.Size = memberSize; // Adjust offset for next item constantBufferOffset += memberSize; reflectionConstantBuffer.Members[index] = member; } reflectionConstantBuffer.Size = constantBufferOffset; } // Find binding var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name); if (resourceBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } } foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform)))) { // Check if we have a variable that starts or ends with this name (in case of samplers) // TODO: Have real AST support for all the list in Keywords.glsl if (variable.Type.Name.Text.Contains("sampler1D") || variable.Type.Name.Text.Contains("sampler2D") || variable.Type.Name.Text.Contains("sampler3D") || variable.Type.Name.Text.Contains("samplerCube")) { // TODO: Make more robust var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName)); var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName)); if (textureBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage); } if (samplerBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage); } } else { var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name); if (resourceBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } } } } // Output the result var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage); if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320) { glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder"; } // Write shader glslShaderWriter.Visit(glslShader); var shaderString = glslShaderWriter.Text; // Build shader source var glslShaderCode = new StringBuilder(); // Append some header depending on target //if (isOpenGLES) //{ // if (isOpenGLES3) // { // glslShaderCode // .AppendLine("#version 300 es") // TODO: 310 version? // .AppendLine(); // } // // if (pipelineStage == PipelineStage.Pixel) // glslShaderCode // .AppendLine("precision highp float;") // .AppendLine(); //} //else //{ // glslShaderCode // .AppendLine("#version 420") // .AppendLine() // .AppendLine("#define samplerBuffer sampler2D") // .AppendLine("#define isamplerBuffer isampler2D") // .AppendLine("#define usamplerBuffer usampler2D") // .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)"); // //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)"); //} glslShaderCode.Append(shaderString); var realShaderSource = glslShaderCode.ToString(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP // optimize shader try { var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, shaderPlatform, shaderVersion, pipelineStage == PipelineStage.Vertex); if (!String.IsNullOrEmpty(optShaderSource)) { realShaderSource = optShaderSource; } } catch (Exception e) { shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n{0}", e.Message); } #else shaderBytecodeResult.Warning("GLSL optimized has not been executed because it is currently not supported on this platform."); #endif return(realShaderSource); }
private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, IDictionary <int, string> inputAttributeNames, Dictionary <string, int> resourceBindings, string sourceFilename = null) { if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && renderTargetCount > 1) { shaderBytecodeResult.Error("OpenGL ES 2 does not support multiple render targets."); } PipelineStage pipelineStage = PipelineStage.None; switch (stage) { case ShaderStage.Vertex: pipelineStage = PipelineStage.Vertex; break; case ShaderStage.Pixel: pipelineStage = PipelineStage.Pixel; break; case ShaderStage.Geometry: shaderBytecodeResult.Error("Geometry stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Hull: shaderBytecodeResult.Error("Hull stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Domain: shaderBytecodeResult.Error("Domain stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Compute: shaderBytecodeResult.Error("Compute stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; default: shaderBytecodeResult.Error("Unknown shader profile."); break; } if (shaderBytecodeResult.HasErrors) { return(null); } Shader glslShader; // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter // TODO: support that directly in HlslToGlslConvertor? if (entryPoint == null) { glslShader = null; } else { // Convert from HLSL to GLSL // Note that for now we parse from shader as a string, but we could simply clone effectPass.Shader to avoid multiple parsing. var glslConvertor = new ShaderConverter(shaderPlatform, shaderVersion); glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, inputAttributeNames, shaderBytecodeResult); if (glslShader == null || shaderBytecodeResult.HasErrors) { return(null); } foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>()) { // Update constant buffer itself (first time only) var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0); if (reflectionConstantBuffer != null) { // Used to compute constant buffer size and member offsets (std140 rule) int constantBufferOffset = 0; // Fill members for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++) { var member = reflectionConstantBuffer.Members[index]; // Properly compute size and offset according to std140 rules var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset); // Store size/offset info member.Offset = constantBufferOffset; member.Size = memberSize; // Adjust offset for next item constantBufferOffset += memberSize; reflectionConstantBuffer.Members[index] = member; } reflectionConstantBuffer.Size = constantBufferOffset; } // Find binding var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name); if (resourceBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } } foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform)))) { // Check if we have a variable that starts or ends with this name (in case of samplers) // TODO: Have real AST support for all the list in Keywords.glsl if (variable.Type.Name.Text.Contains("sampler1D") || variable.Type.Name.Text.Contains("sampler2D") || variable.Type.Name.Text.Contains("sampler3D") || variable.Type.Name.Text.Contains("samplerCube") || variable.Type.Name.Text.Contains("samplerBuffer")) { // TODO: Make more robust var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName)); var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName)); if (textureBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage); } if (samplerBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage); } } else { var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name); if (resourceBindingIndex != -1) { MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } } } if (shaderPlatform == GlslShaderPlatform.Vulkan) { // Defines the ordering of resource groups in Vulkan. This is mirrored in the PipelineState var resourceGroups = reflection.ResourceBindings.Select(x => x.ResourceGroup ?? "Globals").Distinct().ToList(); // Register "NoSampler", required by HLSL=>GLSL translation to support HLSL such as texture.Load(). var noSampler = new EffectResourceBindingDescription { KeyInfo = { KeyName = "NoSampler" }, RawName = "NoSampler", Class = EffectParameterClass.Sampler, SlotStart = -1, SlotCount = 1 }; reflection.ResourceBindings.Add(noSampler); var bindings = resourceGroups.SelectMany(resourceGroup => reflection.ResourceBindings .Where(x => x.ResourceGroup == resourceGroup || (x.ResourceGroup == null && resourceGroup == "Globals")) .GroupBy(x => new { KeyName = x.KeyInfo.KeyName, RawName = x.RawName, Class = x.Class, Type = x.Type, SlotCount = x.SlotCount, LogicalGroup = x.LogicalGroup }) .OrderBy(x => x.Key.Class == EffectParameterClass.ConstantBuffer ? 0 : 1)) .ToList(); // Add layout(set, bindings) qualifier to all constant buffers foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>()) { var layoutBindingIndex = bindings.IndexOf(x => x.Key.RawName == constantBuffer.Name); if (layoutBindingIndex != -1) { var layoutQualifier = constantBuffer.Qualifiers.OfType <Xenko.Core.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new Xenko.Core.Shaders.Ast.Glsl.LayoutQualifier(); constantBuffer.Qualifiers |= layoutQualifier; } //layoutQualifier.Layouts.Add(new LayoutKeyValue("set", resourceGroups.IndexOf(resourceGroup))); layoutQualifier.Layouts.Add(new LayoutKeyValue("set", 0)); layoutQualifier.Layouts.Add(new LayoutKeyValue("binding", layoutBindingIndex + 1)); resourceBindings.Add(bindings[layoutBindingIndex].Key.KeyName, layoutBindingIndex + 1); } } // Add layout(set, bindings) qualifier to all other uniforms foreach (var variable in glslShader.Declarations.OfType <Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform)))) { var layoutBindingIndex = bindings.IndexOf(x => variable.Name.Text.StartsWith(x.Key.RawName)); if (layoutBindingIndex != -1) { var layoutQualifier = variable.Qualifiers.OfType <Xenko.Core.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new Xenko.Core.Shaders.Ast.Glsl.LayoutQualifier(); variable.Qualifiers |= layoutQualifier; } //layoutQualifier.Layouts.Add(new LayoutKeyValue("set", resourceGroups.IndexOf(resourceGroup))); layoutQualifier.Layouts.Add(new LayoutKeyValue("set", 0)); layoutQualifier.Layouts.Add(new LayoutKeyValue("binding", layoutBindingIndex + 1)); resourceBindings.Add(bindings[layoutBindingIndex].Key.KeyName, layoutBindingIndex + 1); } } } } // Output the result var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage); if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320) { glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder"; } // Write shader glslShaderWriter.Visit(glslShader); var shaderString = glslShaderWriter.Text; // Build shader source var glslShaderCode = new StringBuilder(); // Append some header depending on target //if (isOpenGLES) //{ // if (isOpenGLES3) // { // glslShaderCode // .AppendLine("#version 300 es") // TODO: 310 version? // .AppendLine(); // } // // if (pipelineStage == PipelineStage.Pixel) // glslShaderCode // .AppendLine("precision highp float;") // .AppendLine(); //} //else //{ // glslShaderCode // .AppendLine("#version 420") // .AppendLine() // .AppendLine("#define samplerBuffer sampler2D") // .AppendLine("#define isamplerBuffer isampler2D") // .AppendLine("#define usamplerBuffer usampler2D") // .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)"); // //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)"); //} glslShaderCode.Append(shaderString); var realShaderSource = glslShaderCode.ToString(); return(realShaderSource); }
private string RunOptimizer(ShaderBytecodeResult shaderBytecodeResult, string baseShader, GlslShaderPlatform shaderPlatform, int shaderVersion, bool vertex) { lock (GlslOptimizerLock) { IntPtr ctx = IntPtr.Zero; var inputShader = baseShader; if (shaderPlatform == GlslShaderPlatform.OpenGLES) { if (shaderVersion >= 300) ctx = glslopt_initialize(2); // kGlslTargetOpenGLES30 else ctx = glslopt_initialize(1); // kGlslTargetOpenGLES20 } else { ctx = glslopt_initialize(0); // kGlslTargetOpenGL } int type = vertex ? 0 : 1; var shader = glslopt_optimize(ctx, type, inputShader, 0); bool optimizeOk = glslopt_get_status(shader); string shaderAsString = null; if (optimizeOk) { IntPtr optShader = glslopt_get_output(shader); shaderAsString = Marshal.PtrToStringAnsi(optShader); } else { IntPtr log = glslopt_get_log(shader); var logAsString = Marshal.PtrToStringAnsi(log); shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n glsl_opt: {0}", string.Join("\r\n glsl_opt: ", logAsString.Split(new[] { "\n", "\r", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))); } glslopt_shader_delete(shader); glslopt_cleanup(ctx); return shaderAsString; } }
private string Compile(string shaderSource, string entryPoint, ShaderStage stage, GlslShaderPlatform shaderPlatform, int shaderVersion, ShaderBytecodeResult shaderBytecodeResult, EffectReflection reflection, string sourceFilename = null) { if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 300 && renderTargetCount > 1) shaderBytecodeResult.Error("OpenGL ES 2 does not support multiple render targets."); PipelineStage pipelineStage = PipelineStage.None; switch (stage) { case ShaderStage.Vertex: pipelineStage = PipelineStage.Vertex; break; case ShaderStage.Pixel: pipelineStage = PipelineStage.Pixel; break; case ShaderStage.Geometry: shaderBytecodeResult.Error("Geometry stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Hull: shaderBytecodeResult.Error("Hull stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Domain: shaderBytecodeResult.Error("Domain stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; case ShaderStage.Compute: shaderBytecodeResult.Error("Compute stage can't be converted to OpenGL. Only Vertex and Pixel shaders are supported"); break; default: shaderBytecodeResult.Error("Unknown shader profile."); break; } if (shaderBytecodeResult.HasErrors) return null; Shader glslShader; // null entry point means no shader. In that case, we return a default function in HlslToGlslWriter // TODO: support that directly in HlslToGlslConvertor? if (entryPoint == null) { glslShader = null; } else { // Convert from HLSL to GLSL // Note that for now we parse from shader as a string, but we could simply clone effectPass.Shader to avoid multiple parsing. var glslConvertor = new ShaderConverter(shaderPlatform, shaderVersion); glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult); if (glslShader == null || shaderBytecodeResult.HasErrors) return null; foreach (var constantBuffer in glslShader.Declarations.OfType<ConstantBuffer>()) { // Update constant buffer itself (first time only) var reflectionConstantBuffer = reflection.ConstantBuffers.FirstOrDefault(x => x.Name == constantBuffer.Name && x.Size == 0); if (reflectionConstantBuffer != null) { // Used to compute constant buffer size and member offsets (std140 rule) int constantBufferOffset = 0; // Fill members for (int index = 0; index < reflectionConstantBuffer.Members.Length; index++) { var member = reflectionConstantBuffer.Members[index]; // Properly compute size and offset according to std140 rules var memberSize = ComputeMemberSize(ref member.Type, ref constantBufferOffset); // Store size/offset info member.Offset = constantBufferOffset; member.Size = memberSize; // Adjust offset for next item constantBufferOffset += memberSize; reflectionConstantBuffer.Members[index] = member; } reflectionConstantBuffer.Size = constantBufferOffset; } // Find binding var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == constantBuffer.Name); if (resourceBindingIndex != -1) MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } foreach (var variable in glslShader.Declarations.OfType<Variable>().Where(x => (x.Qualifiers.Contains(StorageQualifier.Uniform)))) { // Check if we have a variable that starts or ends with this name (in case of samplers) // TODO: Have real AST support for all the list in Keywords.glsl if (variable.Type.Name.Text.Contains("sampler1D") || variable.Type.Name.Text.Contains("sampler2D") || variable.Type.Name.Text.Contains("sampler3D") || variable.Type.Name.Text.Contains("samplerCube")) { // TODO: Make more robust var textureBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().StartsWith(x.RawName)); var samplerBindingIndex = reflection.ResourceBindings.IndexOf(x => variable.Name.ToString().EndsWith(x.RawName)); if (textureBindingIndex != -1) MarkResourceBindingAsUsed(reflection, textureBindingIndex, stage); if (samplerBindingIndex != -1) MarkResourceBindingAsUsed(reflection, samplerBindingIndex, stage); } else { var resourceBindingIndex = reflection.ResourceBindings.IndexOf(x => x.RawName == variable.Name); if (resourceBindingIndex != -1) MarkResourceBindingAsUsed(reflection, resourceBindingIndex, stage); } } } // Output the result var glslShaderWriter = new HlslToGlslWriter(shaderPlatform, shaderVersion, pipelineStage); if (shaderPlatform == GlslShaderPlatform.OpenGLES && shaderVersion < 320) { glslShaderWriter.ExtraHeaders = "#define texelFetchBufferPlaceholder"; } // Write shader glslShaderWriter.Visit(glslShader); var shaderString = glslShaderWriter.Text; // Build shader source var glslShaderCode = new StringBuilder(); // Append some header depending on target //if (isOpenGLES) //{ // if (isOpenGLES3) // { // glslShaderCode // .AppendLine("#version 300 es") // TODO: 310 version? // .AppendLine(); // } // // if (pipelineStage == PipelineStage.Pixel) // glslShaderCode // .AppendLine("precision highp float;") // .AppendLine(); //} //else //{ // glslShaderCode // .AppendLine("#version 420") // .AppendLine() // .AppendLine("#define samplerBuffer sampler2D") // .AppendLine("#define isamplerBuffer isampler2D") // .AppendLine("#define usamplerBuffer usampler2D") // .AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)"); // //.AppendLine("#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)"); //} glslShaderCode.Append(shaderString); var realShaderSource = glslShaderCode.ToString(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP // optimize shader try { var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, shaderPlatform, shaderVersion, pipelineStage == PipelineStage.Vertex); if (!String.IsNullOrEmpty(optShaderSource)) realShaderSource = optShaderSource; } catch (Exception e) { shaderBytecodeResult.Warning("Could not run GLSL optimizer:\n{0}", e.Message); } #else shaderBytecodeResult.Warning("GLSL optimized has not been executed because it is currently not supported on this platform."); #endif return realShaderSource; }