private void LinkConstant(string cbName, Variable variable, LocalParameterKey parameterKey) { // If the constant buffer is not present, add it var constantBuffer = effectReflection.ConstantBuffers.FirstOrDefault(buffer => buffer.Name == cbName); if (constantBuffer == null) { constantBuffer = new EffectConstantBufferDescription() { Name = cbName, Type = ConstantBufferType.ConstantBuffer }; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectResourceBindingDescription { KeyInfo = { KeyName = cbName }, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.ConstantBuffer, RawName = cbName, SlotStart = -1, SlotCount = 1, ResourceGroup = cbName }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List <EffectValueDescription>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectValueDescription { KeyInfo = { KeyName = parameterKey.Name, }, LogicalGroup = (string)variable.GetTag(XenkoTags.LogicalGroup), Type = parameterKey.Type, RawName = variable.Name, }; members.Add(binding); }
private static void LinkVariable(EffectReflection reflection, string variableName, LocalParameterKey parameterKey, int slotCount) { var binding = new EffectResourceBindingDescription { KeyInfo = { KeyName = parameterKey.Name }, Class = parameterKey.Type.Class, Type = parameterKey.Type.Type, RawName = variableName, SlotStart = -1, SlotCount = slotCount > 0 ? slotCount : 1, ResourceGroup = parameterKey.ResourceGroup, LogicalGroup = parameterKey.LogicalGroup }; reflection.ResourceBindings.Add(binding); }
private static void UpdateResourceBindingKey(ref EffectResourceBindingDescription binding) { var keyName = binding.KeyInfo.KeyName; switch (binding.Class) { case EffectParameterClass.Sampler: binding.KeyInfo.Key = FindOrCreateResourceKey <SamplerState>(keyName); break; case EffectParameterClass.ConstantBuffer: case EffectParameterClass.TextureBuffer: case EffectParameterClass.ShaderResourceView: case EffectParameterClass.UnorderedAccessView: switch (binding.Type) { case EffectParameterType.Buffer: case EffectParameterType.ConstantBuffer: case EffectParameterType.TextureBuffer: case EffectParameterType.AppendStructuredBuffer: case EffectParameterType.ByteAddressBuffer: case EffectParameterType.ConsumeStructuredBuffer: case EffectParameterType.StructuredBuffer: case EffectParameterType.RWBuffer: case EffectParameterType.RWStructuredBuffer: case EffectParameterType.RWByteAddressBuffer: binding.KeyInfo.Key = FindOrCreateResourceKey <Buffer>(keyName); break; case EffectParameterType.Texture: case EffectParameterType.Texture1D: case EffectParameterType.Texture1DArray: case EffectParameterType.RWTexture1D: case EffectParameterType.RWTexture1DArray: case EffectParameterType.Texture2D: case EffectParameterType.Texture2DArray: case EffectParameterType.Texture2DMultisampled: case EffectParameterType.Texture2DMultisampledArray: case EffectParameterType.RWTexture2D: case EffectParameterType.RWTexture2DArray: case EffectParameterType.TextureCube: case EffectParameterType.TextureCubeArray: case EffectParameterType.RWTexture3D: case EffectParameterType.Texture3D: binding.KeyInfo.Key = FindOrCreateResourceKey <Texture>(keyName); break; } break; } if (binding.KeyInfo.Key == null) { throw new InvalidOperationException(string.Format("Unable to find/generate key [{0}] with unsupported type [{1}/{2}]", binding.KeyInfo.KeyName, binding.Class, binding.Type)); } }
/// <summary> /// Inserts the data in the list if this is a copy of a previously set one. /// </summary> /// <param name="data">The data.</param> /// <param name="index">The index in the list.</param> /// <param name="bindings">The list of bindings.</param> /// <returns>The new index of the data.</returns> private static int GetReflexionIndex(EffectResourceBindingDescription data, int index, FastList <EffectResourceBindingDescription> bindings) { if (data.SlotCount != 0) { // slot count has been specified, this means that this resource was already configured // We have to create a new entry for the data var newIndex = bindings.Count; bindings.Add(data); return(newIndex); } return(index); }
private EffectResourceBindingDescription GetResourceBinding(SharpDX.D3DCompiler.InputBindingDescription bindingDescriptionRaw, string name, LoggerResult log) { var paramClass = EffectParameterClass.Object; var paramType = EffectParameterType.Void; switch (bindingDescriptionRaw.Type) { case SharpDX.D3DCompiler.ShaderInputType.TextureBuffer: paramType = EffectParameterType.TextureBuffer; paramClass = EffectParameterClass.TextureBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.ConstantBuffer: paramType = EffectParameterType.ConstantBuffer; paramClass = EffectParameterClass.ConstantBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.Texture: paramClass = EffectParameterClass.ShaderResourceView; switch (bindingDescriptionRaw.Dimension) { case SharpDX.Direct3D.ShaderResourceViewDimension.Buffer: paramType = EffectParameterType.Buffer; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1D: paramType = EffectParameterType.Texture1D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1DArray: paramType = EffectParameterType.Texture1DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D: paramType = EffectParameterType.Texture2D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DArray: paramType = EffectParameterType.Texture2DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DMultisampled: paramType = EffectParameterType.Texture2DMultisampled; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DMultisampledArray: paramType = EffectParameterType.Texture2DMultisampledArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture3D: paramType = EffectParameterType.Texture3D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.TextureCube: paramType = EffectParameterType.TextureCube; break; case SharpDX.Direct3D.ShaderResourceViewDimension.TextureCubeArray: paramType = EffectParameterType.TextureCubeArray; break; } break; case SharpDX.D3DCompiler.ShaderInputType.Structured: paramClass = EffectParameterClass.ShaderResourceView; paramType = EffectParameterType.StructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.ByteAddress: paramClass = EffectParameterClass.ShaderResourceView; paramType = EffectParameterType.ByteAddressBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWTyped: paramClass = EffectParameterClass.UnorderedAccessView; switch (bindingDescriptionRaw.Dimension) { case SharpDX.Direct3D.ShaderResourceViewDimension.Buffer: paramType = EffectParameterType.RWBuffer; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1D: paramType = EffectParameterType.RWTexture1D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1DArray: paramType = EffectParameterType.RWTexture1DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D: paramType = EffectParameterType.RWTexture2D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DArray: paramType = EffectParameterType.RWTexture2DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture3D: paramType = EffectParameterType.RWTexture3D; break; } break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWByteAddress: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWByteAddressBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewAppendStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.AppendStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewConsumeStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.ConsumeStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWStructuredWithCounter: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.Sampler: paramClass = EffectParameterClass.Sampler; paramType = EffectParameterType.Sampler; break; } var binding = new EffectResourceBindingDescription() { KeyInfo = { KeyName = name, }, RawName = bindingDescriptionRaw.Name, Class = paramClass, Type = paramType, SlotStart = bindingDescriptionRaw.BindPoint, SlotCount = bindingDescriptionRaw.BindCount, }; return(binding); }
/// <summary> /// Create or updates the reflection for this shader /// </summary> /// <param name="effectReflection">the reflection from the hlsl</param> /// <param name="stage">the shader pipeline stage</param> private void CreateReflection(EffectReflection effectReflection, ShaderStage stage) { int currentProgram; GL.GetInteger(GetPName.CurrentProgram, out currentProgram); GL.UseProgram(ProgramId); int uniformBlockCount; GL.GetProgram(ProgramId, XkActiveUniformBlocks, out uniformBlockCount); var validConstantBuffers = new bool[effectReflection.ConstantBuffers.Count]; for (int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { // TODO: get previous name to find te actual constant buffer in the reflexion #if STRIDE_GRAPHICS_API_OPENGLES const int sbCapacity = 128; int length; var sb = new StringBuilder(sbCapacity); GL.GetActiveUniformBlockName(ProgramId, uniformBlockIndex, sbCapacity, out length, sb); var constantBufferName = sb.ToString(); #else var constantBufferName = GL.GetActiveUniformBlockName(ProgramId, uniformBlockIndex); #endif var constantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == constantBufferName); if (constantBufferDescriptionIndex == -1) { reflectionResult.Error($"Unable to find the constant buffer description [{constantBufferName}]"); return; } var constantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferName); if (constantBufferIndex == -1) { reflectionResult.Error($"Unable to find the constant buffer [{constantBufferName}]"); return; } var constantBufferDescription = effectReflection.ConstantBuffers[constantBufferDescriptionIndex]; var constantBuffer = effectReflection.ResourceBindings[constantBufferIndex]; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockDataSize, out constantBufferDescription.Size); int uniformCount; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniforms, out uniformCount); // set the binding GL.UniformBlockBinding(ProgramId, uniformBlockIndex, uniformBlockIndex); // Read uniforms desc var uniformIndices = new int[uniformCount]; var uniformOffsets = new int[uniformCount]; var uniformTypes = new int[uniformCount]; var uniformNames = new string[uniformCount]; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniformIndices, uniformIndices); GL.GetActiveUniforms(ProgramId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformOffset, uniformOffsets); GL.GetActiveUniforms(ProgramId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformType, uniformTypes); for (int uniformIndex = 0; uniformIndex < uniformIndices.Length; ++uniformIndex) { #if STRIDE_GRAPHICS_API_OPENGLES int size; ActiveUniformType aut; GL.GetActiveUniform(ProgramId, uniformIndices[uniformIndex], sbCapacity, out length, out size, out aut, sb); uniformNames[uniformIndex] = sb.ToString(); #else uniformNames[uniformIndex] = GL.GetActiveUniformName(ProgramId, uniformIndices[uniformIndex]); #endif } // Reoder by offset var indexMapping = uniformIndices.Select((x, i) => new UniformMergeInfo { Offset = uniformOffsets[i], Type = (ActiveUniformType)uniformTypes[i], Name = uniformNames[i], NextOffset = 0 }).OrderBy(x => x.Offset).ToArray(); indexMapping.Last().NextOffset = constantBufferDescription.Size; // Fill next offsets for (int i = 1; i < indexMapping.Length; ++i) { indexMapping[i - 1].NextOffset = indexMapping[i].Offset; } // Group arrays/structures into one variable (std140 layout is enough for offset determinism inside arrays/structures) indexMapping = indexMapping.GroupBy(x => { // Use only first part of name (ignore structure/array part) var name = x.Name; if (name.Contains(".")) { name = name.Substring(0, name.IndexOf('.')); } if (name.Contains("[")) { name = name.Substring(0, name.IndexOf('[')); } return(name); }) .Select(x => { var result = x.First(); result.NextOffset = x.Last().NextOffset; // Check weither it's an array or a struct int dotIndex = result.Name.IndexOf('.'); int arrayIndex = result.Name.IndexOf('['); if (x.Count() > 1 && arrayIndex == -1 && dotIndex == -1) { throw new InvalidOperationException(); } // TODO: Type processing result.Name = x.Key; return(result); }).ToArray(); foreach (var variableIndexGroup in indexMapping) { var variableIndex = -1; for (var tentativeIndex = 0; tentativeIndex < constantBufferDescription.Members.Length; ++tentativeIndex) { if (constantBufferDescription.Members[tentativeIndex].RawName == variableIndexGroup.Name) { variableIndex = tentativeIndex; break; } } if (variableIndex == -1) { reflectionResult.Error($"Unable to find uniform [{variableIndexGroup.Name}] in constant buffer [{constantBufferName}]"); continue; } var variable = constantBufferDescription.Members[variableIndex]; variable.Type.Type = GetTypeFromActiveUniformType(variableIndexGroup.Type); variable.Offset = variableIndexGroup.Offset; variable.Size = variableIndexGroup.NextOffset - variableIndexGroup.Offset; constantBufferDescription.Members[variableIndex] = variable; } constantBufferDescription.Type = ConstantBufferType.ConstantBuffer; constantBuffer.SlotCount = 1; // constant buffers are not arrays constantBuffer.SlotStart = uniformBlockIndex; constantBuffer.Stage = stage; // store the new values validConstantBuffers[constantBufferDescriptionIndex] = true; effectReflection.ConstantBuffers[constantBufferDescriptionIndex] = constantBufferDescription; effectReflection.ResourceBindings[constantBufferIndex] = constantBuffer; } //#endif // Remove unecessary cbuffer and resource bindings // Register textures, samplers, etc... //TODO: (?) non texture/buffer uniform outside of a block { // 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); int activeUniformCount; GL.GetProgram(ProgramId, GetProgramParameterName.ActiveUniforms, out activeUniformCount); #if !STRIDE_GRAPHICS_API_OPENGLES var uniformTypes = new int[activeUniformCount]; GL.GetActiveUniforms(ProgramId, activeUniformCount, Enumerable.Range(0, activeUniformCount).ToArray(), ActiveUniformParameter.UniformType, uniformTypes); #endif int textureUnitCount = 0; const int sbCapacity = 128; var sb = new StringBuilder(sbCapacity); for (int activeUniformIndex = 0; activeUniformIndex < activeUniformCount; ++activeUniformIndex) { #if !STRIDE_GRAPHICS_API_OPENGLES var uniformType = (ActiveUniformType)uniformTypes[activeUniformIndex]; var uniformName = GL.GetActiveUniformName(ProgramId, activeUniformIndex); #else ActiveUniformType uniformType; int uniformCount; int length; GL.GetActiveUniform(ProgramId, activeUniformIndex, sbCapacity, out length, out uniformCount, out uniformType, sb); var uniformName = sb.ToString(); //this is a special OpenglES case , it is declared as built in uniform, and the driver will take care of it, we just need to ignore it here if (uniformName.StartsWith("gl_DepthRange")) { continue; } #endif switch (uniformType) { #if !STRIDE_GRAPHICS_API_OPENGLES case ActiveUniformType.Sampler1D: case ActiveUniformType.Sampler1DShadow: case ActiveUniformType.IntSampler1D: case ActiveUniformType.UnsignedIntSampler1D: case ActiveUniformType.SamplerBuffer: case ActiveUniformType.UnsignedIntSamplerBuffer: case ActiveUniformType.IntSamplerBuffer: #endif case ActiveUniformType.Sampler2D: case ActiveUniformType.Sampler2DShadow: case ActiveUniformType.Sampler3D: // TODO: remove Texture3D that is not available in OpenGL ES 2 case ActiveUniformType.SamplerCube: case ActiveUniformType.IntSampler2D: case ActiveUniformType.IntSampler3D: case ActiveUniformType.IntSamplerCube: case ActiveUniformType.UnsignedIntSampler2D: case ActiveUniformType.UnsignedIntSampler3D: case ActiveUniformType.UnsignedIntSamplerCube: var uniformIndex = GL.GetUniformLocation(ProgramId, uniformName); // Temporary way to scan which texture and sampler created this texture_sampler variable (to fix with new HLSL2GLSL converter) var startIndex = -1; var textureReflectionIndex = -1; var samplerReflectionIndex = -1; do { int middlePart = uniformName.IndexOf('_', startIndex + 1); var textureName = middlePart != -1 ? uniformName.Substring(0, middlePart) : uniformName; var samplerName = middlePart != -1 ? uniformName.Substring(middlePart + 1) : null; textureReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == textureName); samplerReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == samplerName); if (textureReflectionIndex != -1 && samplerReflectionIndex != -1) { break; } startIndex = middlePart; } while (startIndex != -1); if (startIndex == -1 || textureReflectionIndex == -1 || samplerReflectionIndex == -1) { reflectionResult.Error($"Unable to find sampler and texture corresponding to [{uniformName}]"); continue; // Error } var textureReflection = effectReflection.ResourceBindings[textureReflectionIndex]; var samplerReflection = effectReflection.ResourceBindings[samplerReflectionIndex]; // Contrary to Direct3D, samplers and textures are part of the same object in OpenGL // Since we are exposing the Direct3D representation, a single sampler parameter key can be used for several textures, a single texture can be used with several samplers. // When such a case is detected, we need to duplicate the resource binding. textureReflectionIndex = GetReflexionIndex(textureReflection, textureReflectionIndex, effectReflection.ResourceBindings); samplerReflectionIndex = GetReflexionIndex(samplerReflection, samplerReflectionIndex, effectReflection.ResourceBindings); // Update texture uniform mapping GL.Uniform1(uniformIndex, textureUnitCount); textureReflection.Stage = stage; //textureReflection.Param.RawName = uniformName; textureReflection.Type = GetTypeFromActiveUniformType(uniformType); textureReflection.Class = EffectParameterClass.ShaderResourceView; textureReflection.SlotStart = textureUnitCount; textureReflection.SlotCount = 1; // TODO: texture arrays samplerReflection.Stage = stage; samplerReflection.Class = EffectParameterClass.Sampler; samplerReflection.SlotStart = textureUnitCount; samplerReflection.SlotCount = 1; // TODO: texture arrays effectReflection.ResourceBindings[textureReflectionIndex] = textureReflection; effectReflection.ResourceBindings[samplerReflectionIndex] = samplerReflection; Textures.Add(new Texture(textureUnitCount)); textureUnitCount++; break; } } // Remove any optimized resource binding effectReflection.ResourceBindings.RemoveAll(x => x.SlotStart == -1); effectReflection.ConstantBuffers = effectReflection.ConstantBuffers.Where((cb, i) => validConstantBuffers[i]).ToList(); } GL.UseProgram(currentProgram); }
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 void LinkConstant(string cbName, Variable variable, LocalParameterKey parameterKey) { // If the constant buffer is not present, add it var constantBuffer = effectReflection.ConstantBuffers.FirstOrDefault(buffer => buffer.Name == cbName); if (constantBuffer == null) { constantBuffer = new EffectConstantBufferDescription() {Name = cbName, Type = ConstantBufferType.ConstantBuffer}; effectReflection.ConstantBuffers.Add(constantBuffer); var constantBufferBinding = new EffectResourceBindingDescription { KeyInfo = { KeyName = cbName }, Class = EffectParameterClass.ConstantBuffer, Type = EffectParameterType.ConstantBuffer, RawName = cbName, SlotStart = -1, SlotCount = 1, ResourceGroup = cbName }; effectReflection.ResourceBindings.Add(constantBufferBinding); valueBindings.Add(constantBuffer, new List<EffectValueDescription>()); } // Get the list of members of this constant buffer var members = valueBindings[constantBuffer]; var binding = new EffectValueDescription { KeyInfo = { KeyName = parameterKey.Name, }, LogicalGroup = (string)variable.GetTag(XenkoTags.LogicalGroup), Type = parameterKey.Type, RawName = variable.Name, }; members.Add(binding); }
private static void LinkVariable(EffectReflection reflection, string variableName, LocalParameterKey parameterKey, int slotCount) { var binding = new EffectResourceBindingDescription { KeyInfo = { KeyName = parameterKey.Name }, Class = parameterKey.Type.Class, Type = parameterKey.Type.Type, RawName = variableName, SlotStart = -1, SlotCount = slotCount > 0 ? slotCount : 1, ResourceGroup = parameterKey.ResourceGroup, LogicalGroup = parameterKey.LogicalGroup }; reflection.ResourceBindings.Add(binding); }
private EffectResourceBindingDescription GetResourceBinding(SharpDX.D3DCompiler.InputBindingDescription bindingDescriptionRaw, string name, LoggerResult log) { var paramClass = EffectParameterClass.Object; var paramType = EffectParameterType.Void; switch (bindingDescriptionRaw.Type) { case SharpDX.D3DCompiler.ShaderInputType.TextureBuffer: paramType = EffectParameterType.TextureBuffer; paramClass = EffectParameterClass.TextureBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.ConstantBuffer: paramType = EffectParameterType.ConstantBuffer; paramClass = EffectParameterClass.ConstantBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.Texture: paramClass = EffectParameterClass.ShaderResourceView; switch (bindingDescriptionRaw.Dimension) { case SharpDX.Direct3D.ShaderResourceViewDimension.Buffer: paramType = EffectParameterType.Buffer; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1D: paramType = EffectParameterType.Texture1D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1DArray: paramType = EffectParameterType.Texture1DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D: paramType = EffectParameterType.Texture2D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DArray: paramType = EffectParameterType.Texture2DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DMultisampled: paramType = EffectParameterType.Texture2DMultisampled; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DMultisampledArray: paramType = EffectParameterType.Texture2DMultisampledArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture3D: paramType = EffectParameterType.Texture3D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.TextureCube: paramType = EffectParameterType.TextureCube; break; case SharpDX.Direct3D.ShaderResourceViewDimension.TextureCubeArray: paramType = EffectParameterType.TextureCubeArray; break; } break; case SharpDX.D3DCompiler.ShaderInputType.Structured: paramClass = EffectParameterClass.ShaderResourceView; paramType = EffectParameterType.StructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.ByteAddress: paramClass = EffectParameterClass.ShaderResourceView; paramType = EffectParameterType.ByteAddressBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWTyped: paramClass = EffectParameterClass.UnorderedAccessView; switch (bindingDescriptionRaw.Dimension) { case SharpDX.Direct3D.ShaderResourceViewDimension.Buffer: paramType = EffectParameterType.RWBuffer; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1D: paramType = EffectParameterType.RWTexture1D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture1DArray: paramType = EffectParameterType.RWTexture1DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D: paramType = EffectParameterType.RWTexture2D; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture2DArray: paramType = EffectParameterType.RWTexture2DArray; break; case SharpDX.Direct3D.ShaderResourceViewDimension.Texture3D: paramType = EffectParameterType.RWTexture3D; break; } break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWByteAddress: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWByteAddressBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewAppendStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.AppendStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewConsumeStructured: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.ConsumeStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.UnorderedAccessViewRWStructuredWithCounter: paramClass = EffectParameterClass.UnorderedAccessView; paramType = EffectParameterType.RWStructuredBuffer; break; case SharpDX.D3DCompiler.ShaderInputType.Sampler: paramClass = EffectParameterClass.Sampler; paramType = EffectParameterType.Sampler; break; } var binding = new EffectResourceBindingDescription() { KeyInfo = { KeyName = name, }, RawName = bindingDescriptionRaw.Name, Class = paramClass, Type = paramType, SlotStart = bindingDescriptionRaw.BindPoint, SlotCount = bindingDescriptionRaw.BindCount, }; return binding; }