private Shader(GraphicsDevice device, ShaderStage shaderStage, byte[] shaderStageBytecode) : base(device) { this.stage = shaderStage; var shaderStageGl = ConvertShaderStage(shaderStage); // Decode shader StageBytecode var binarySerializationReader = new BinarySerializationReader(new MemoryStream(shaderStageBytecode)); var shaderBytecodeData = new OpenGLShaderBytecodeData(); shaderBytecodeData.Serialize(binarySerializationReader, ArchiveMode.Deserialize); using (GraphicsDevice.UseOpenGLCreationContext()) { resourceId = GL.CreateShader(shaderStageGl); if (shaderBytecodeData.IsBinary) { GL.ShaderBinary(1, ref resourceId, (BinaryFormat)shaderBytecodeData.BinaryFormat, shaderBytecodeData.Binary, shaderBytecodeData.Binary.Length); } else { GL.ShaderSource(resourceId, shaderBytecodeData.Source); GL.CompileShader(resourceId); var log = GL.GetShaderInfoLog(resourceId); int compileStatus; GL.GetShader(resourceId, ShaderParameter.CompileStatus, out compileStatus); if (compileStatus != 1) throw new InvalidOperationException(string.Format("Error while compiling GLSL shader: {0}", log)); } } }
internal Shader(GraphicsDevice device, BinaryReader reader) { this.GraphicsDevice = device; this.Stage = reader.ReadBoolean() ? ShaderStage.Vertex : ShaderStage.Pixel; int count = (int) reader.ReadUInt16(); byte[] bytes = reader.ReadBytes(count); int length1 = (int) reader.ReadByte(); this.Samplers = new SamplerInfo[length1]; for (int index = 0; index < length1; ++index) { this.Samplers[index].type = (SamplerType) reader.ReadByte(); this.Samplers[index].index = (int) reader.ReadByte(); this.Samplers[index].name = reader.ReadString(); this.Samplers[index].parameter = (int) reader.ReadByte(); } int length2 = (int) reader.ReadByte(); this.CBuffers = new int[length2]; for (int index = 0; index < length2; ++index) this.CBuffers[index] = (int) reader.ReadByte(); this._glslCode = Encoding.ASCII.GetString(bytes); this.HashKey = Hash.ComputeHash(bytes); int length3 = (int) reader.ReadByte(); this._attributes = new Shader.Attribute[length3]; for (int index = 0; index < length3; ++index) { this._attributes[index].name = reader.ReadString(); this._attributes[index].usage = (VertexElementUsage) reader.ReadByte(); this._attributes[index].index = (int) reader.ReadByte(); this._attributes[index].format = reader.ReadInt16(); } }
private Shader(GraphicsDevice device, ShaderStage shaderStage, byte[] shaderBytecode) : base(device) { this.stage = shaderStage; switch (shaderStage) { case ShaderStage.Vertex: NativeDeviceChild = new VertexShader(device.NativeDevice, shaderBytecode); NativeInputSignature = shaderBytecode; break; case ShaderStage.Hull: NativeDeviceChild = new HullShader(device.NativeDevice, shaderBytecode); break; case ShaderStage.Domain: NativeDeviceChild = new DomainShader(device.NativeDevice, shaderBytecode); break; case ShaderStage.Geometry: NativeDeviceChild = new GeometryShader(device.NativeDevice, shaderBytecode); break; case ShaderStage.Pixel: NativeDeviceChild = new PixelShader(device.NativeDevice, shaderBytecode); break; case ShaderStage.Compute: NativeDeviceChild = new ComputeShader(device.NativeDevice, shaderBytecode); break; default: throw new ArgumentOutOfRangeException("shaderStage"); } }
public static ShaderSamplerSetCommand Create(ShaderStage stage, IEnumerable<SamplerResource> resources = null) { if (resources == null) { resources = new SamplerResource[] { }; } return new ShaderSamplerSetCommand { Stage = stage, Samplers = resources.Select(r => r.ID).ToArray(), }; }
public static string GetText(ShaderStage stage) { switch (stage) { case ShaderStage.Vertex: return VertexText; case ShaderStage.Pixel: return PixelText; case ShaderStage.Geometry: return GeometryText; case ShaderStage.Hull: return HullText; case ShaderStage.Domain: return DomainText; case ShaderStage.Compute: return ComputeText; default: throw new ArgumentOutOfRangeException("stage"); } }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="compilerParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null) { var isOpenGLES = compilerParameters.Get(CompilerParameters.GraphicsPlatformKey) == GraphicsPlatform.OpenGLES; var isOpenGLES3 = compilerParameters.Get(CompilerParameters.GraphicsProfileKey) >= GraphicsProfile.Level_10_0; var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var shader = Compile(shaderSource, entryPoint, stage, isOpenGLES, isOpenGLES3, shaderBytecodeResult, sourceFilename); if (shader == null) return shaderBytecodeResult; if (isOpenGLES) { // store both ES 2 and ES 3 on OpenGL ES platforms var shaderBytecodes = new ShaderLevelBytecode(); if (isOpenGLES3) { shaderBytecodes.DataES3 = shader; shaderBytecodes.DataES2 = null; } else { shaderBytecodes.DataES2 = shader; shaderBytecodes.DataES3 = Compile(shaderSource, entryPoint, stage, true, true, shaderBytecodeResult, sourceFilename); } using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); #if !SILICONSTUDIO_RUNTIME_CORECLR rawData = stream.GetBuffer(); #else // FIXME: Manu: The call to "ToArray()" might be slower than "GetBuffer()" rawData = stream.ToArray(); #endif } } else { // store string on OpenGL platforms rawData = Encoding.ASCII.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return shaderBytecodeResult; }
internal Shader(GraphicsDevice device, BinaryReader reader) { GraphicsDevice = device; var isVertexShader = reader.ReadBoolean(); Stage = isVertexShader ? ShaderStage.Vertex : ShaderStage.Pixel; var shaderLength = reader.ReadInt32(); var shaderBytecode = reader.ReadBytes(shaderLength); var samplerCount = (int)reader.ReadByte(); Samplers = new SamplerInfo[samplerCount]; for (var s = 0; s < samplerCount; s++) { Samplers[s].type = (SamplerType)reader.ReadByte(); Samplers[s].textureSlot = reader.ReadByte(); Samplers[s].samplerSlot = reader.ReadByte(); if (reader.ReadBoolean()) { Samplers[s].state = new SamplerState(); Samplers[s].state.AddressU = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressV = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressW = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.BorderColor = new Color( reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); Samplers[s].state.Filter = (TextureFilter)reader.ReadByte(); Samplers[s].state.MaxAnisotropy = reader.ReadInt32(); Samplers[s].state.MaxMipLevel = reader.ReadInt32(); Samplers[s].state.MipMapLevelOfDetailBias = reader.ReadSingle(); } #if OPENGL Samplers[s].name = reader.ReadString(); #else Samplers[s].name = null; #endif Samplers[s].parameter = reader.ReadByte(); } var cbufferCount = (int)reader.ReadByte(); CBuffers = new int[cbufferCount]; for (var c = 0; c < cbufferCount; c++) CBuffers[c] = reader.ReadByte(); PlatformConstruct(reader, isVertexShader, shaderBytecode); }
/// <summary> /// Construct a ShaderObject defining its main class. /// </summary> /// <param name="shaderStage"> /// A <see cref="ShaderStage"/> indicating the shader stage of this ShaderObject. /// </param> /// <param name="sourcePath"> /// A <see cref="String"/> that specify the file containing the shader object source strings. /// </param> protected ShaderObject(ShaderStage shaderStage, string sourcePath) : this(shaderStage) { try { if (sourcePath == null) throw new ArgumentNullException("sourcePath"); // Store shader path (for debugging) _SourcePath = sourcePath; } catch { // Avoid finalizer assertion failure (don't call dispose since it's virtual) GC.SuppressFinalize(this); throw; } }
private static ShaderType ConvertShaderStage(ShaderStage shaderStage) { switch (shaderStage) { case ShaderStage.Pixel: return ShaderType.FragmentShader; case ShaderStage.Vertex: return ShaderType.VertexShader; #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES case ShaderStage.Geometry: return ShaderType.GeometryShader; #endif default: throw new NotSupportedException(); } }
internal Shader(GraphicsDevice device, BinaryReader reader) { this.GraphicsDevice = device; this.Stage = reader.ReadBoolean() ? ShaderStage.Vertex : ShaderStage.Pixel; int count = (int) reader.ReadUInt16(); byte[] bytes = reader.ReadBytes(count); int length1 = (int) reader.ReadByte(); this.Samplers = new SamplerInfo[length1]; for (int index = 0; index < length1; ++index) { this.Samplers[index].type = (SamplerType) reader.ReadByte(); this.Samplers[index].textureSlot = (int) reader.ReadByte(); this.Samplers[index].samplerSlot = (int) reader.ReadByte(); if (reader.ReadBoolean()) { this.Samplers[index].state = new SamplerState(); this.Samplers[index].state.AddressU = (TextureAddressMode) reader.ReadByte(); this.Samplers[index].state.AddressV = (TextureAddressMode) reader.ReadByte(); this.Samplers[index].state.AddressW = (TextureAddressMode) reader.ReadByte(); this.Samplers[index].state.Filter = (TextureFilter) reader.ReadByte(); this.Samplers[index].state.MaxAnisotropy = reader.ReadInt32(); this.Samplers[index].state.MaxMipLevel = reader.ReadInt32(); this.Samplers[index].state.MipMapLevelOfDetailBias = reader.ReadSingle(); } this.Samplers[index].name = reader.ReadString(); this.Samplers[index].parameter = (int) reader.ReadByte(); } int length2 = (int) reader.ReadByte(); this.CBuffers = new int[length2]; for (int index = 0; index < length2; ++index) this.CBuffers[index] = (int) reader.ReadByte(); this._glslCode = Encoding.ASCII.GetString(bytes); this.HashKey = Hash.ComputeHash(bytes); int length3 = (int) reader.ReadByte(); this._attributes = new Shader.Attribute[length3]; for (int index = 0; index < length3; ++index) { this._attributes[index].name = reader.ReadString(); this._attributes[index].usage = (VertexElementUsage) reader.ReadByte(); this._attributes[index].index = (int) reader.ReadByte(); this._attributes[index].format = reader.ReadInt16(); } }
public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, ShaderMixinParameters compilerParameters, EffectReflection reflection, string sourceFilename = null) { var isDebug = compilerParameters.Get(CompilerParameters.DebugKey); var profile = compilerParameters.Get(CompilerParameters.GraphicsProfileKey); var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile); var shaderFlags = ShaderFlags.None; if (isDebug) { shaderFlags = ShaderFlags.OptimizationLevel0 | ShaderFlags.Debug; } SharpDX.Configuration.ThrowOnShaderCompileError = false; // Compile using D3DCompiler var compilationResult = SharpDX.D3DCompiler.ShaderBytecode.Compile(shaderSource, entryPoint, shaderModel, shaderFlags, EffectFlags.None, null, null, sourceFilename); var byteCodeResult = new ShaderBytecodeResult(); if (compilationResult.HasErrors) { // Log compilation errors byteCodeResult.Error(compilationResult.Message); } else { // As effect bytecode binary can changed when having debug infos (with d3dcompiler_47), we are calculating a bytecodeId on the stripped version var rawData = compilationResult.Bytecode.Strip(StripFlags.CompilerStripDebugInformation | StripFlags.CompilerStripReflectionData); var bytecodeId = ObjectId.FromBytes(rawData); byteCodeResult.Bytecode = new ShaderBytecode(bytecodeId, compilationResult.Bytecode.Data) { Stage = stage }; // If compilation succeed, then we can update reflection. UpdateReflection(byteCodeResult.Bytecode, reflection, byteCodeResult); if (!string.IsNullOrEmpty(compilationResult.Message)) { byteCodeResult.Warning(compilationResult.Message); } } return byteCodeResult; }
public static ShaderStageFlags Convert(ShaderStage stage) { switch (stage) { case ShaderStage.Vertex: return ShaderStageFlags.Vertex; case ShaderStage.Hull: return ShaderStageFlags.TessellationControl; case ShaderStage.Domain: return ShaderStageFlags.TessellationEvaluation; case ShaderStage.Geometry: return ShaderStageFlags.Geometry; case ShaderStage.Pixel: return ShaderStageFlags.Fragment; case ShaderStage.Compute: return ShaderStageFlags.Compute; default: throw new ArgumentOutOfRangeException(); } }
internal void PlatformApply(GraphicsDevice device, ShaderStage stage, int slot) { if (_cbuffer == null) PlatformInitialize(); // NOTE: We make the assumption here that the caller has // locked the d3dContext for us to use. var d3dContext = GraphicsDevice._d3dContext; // Update the hardware buffer. if (_dirty) { d3dContext.UpdateSubresource(_buffer, _cbuffer); _dirty = false; } // Set the buffer to the right stage. if (stage == ShaderStage.Vertex) d3dContext.VertexShader.SetConstantBuffer(slot, _cbuffer); else d3dContext.PixelShader.SetConstantBuffer(slot, _cbuffer); }
static string GenerateMacros(ShaderStage stage) { var builder = new StringBuilder(1 << 14); #region General builder.AppendLine(@" #define OGL #define OGL3 #define OGL4 #define static"); #endregion #region Types Vectors(T.Float, builder, "#define float{1} {0}"); Vectors(T.Double, builder, "#define double{1} {0}"); Vectors(T.Int, builder, "#define int{1} {0}"); Vectors(T.Uint, builder, "#define uint{1} {0}"); Vectors(T.Bool, builder, "#define bool{1} {0}"); Matrices(T.Float, builder, "#define float{1}x{2} {0}"); Matrices(T.Double, builder, "#define double{1}x{2} {0}"); #endregion #region all Scalars(T.Float | /*T.Double |*/ T.Int | T.Uint, builder, type => string.Format("bool all({0} arg) {{ return arg != {0}(0); }}", type)); AggregateVectors(T.Float | /*T.Double |*/ T.Int | T.Uint, builder, type => string.Format("bool all({0} arg) {{ return", type), type => string.Format(" arg.x != {0}(0)", GetBaseType(type)), (type, i) => string.Format(" && arg.{0} != {1}(0)", VectorElement(i), GetBaseType(type)), type => "; }"); /* AggregateMatrices(T.Float | T.Double, builder, type => string.Format("bool all({0} arg) {{ return", type), type => " arg[0][0] != 0.0", (type, r, c) => string.Format(" && arg[{0}][{1}] != 0.0", r, c), type => "; }");*/ #endregion #region any Scalars(T.Float | /*T.Double |*/ T.Int | T.Uint, builder, type => string.Format("bool any({0} arg) {{ return arg != {0}(0); }}", type)); AggregateVectors(T.Float | /*T.Double |*/ T.Int | T.Uint, builder, type => string.Format("bool any({0} arg) {{ return", type), type => string.Format(" arg.x != {0}(0)", GetBaseType(type)), (type, i) => string.Format(" || arg.{0} != {1}(0)", VectorElement(i), GetBaseType(type)), type => "; }"); /* AggregateMatrices(T.Float | T.Double, builder, type => string.Format("bool any({0} arg) {{ return", type), type => " arg[0][0] != 0.0", (type, r, c) => string.Format(" || arg[{0}][{1}] != 0.0", r, c), type => "; }");*/ #endregion #region atan2 builder.AppendLine("#define atan2(Y, X) atan(Y, X)"); #endregion #region clip if (stage == ShaderStage.Pixel) { builder.AppendLine("void clip(float arg) { if (arg < 0.0) { discard; } }"); AggregateVectors(T.Float, builder, type => string.Format("void clip({0} arg) {{ if (", type), type => "arg.x < 0.0", (type, i) => string.Format(" || arg.{0} < 0.0", VectorElement(i)), type => ") { discard; } }"); /* AggregateMatrices(T.Float, builder, type => string.Format("void clip({0} arg) {{ if (", type), type => "arg[0][0] < 0.0", (type, r, c) => string.Format(" || arg[{0}][{1}] < 0.0", r, c), type => ") { discard; } }");*/ } #endregion #region ddx ddy if (stage == ShaderStage.Pixel) { builder.AppendLine("#define ddx dFdx"); builder.AppendLine("#define ddy dFdy"); } #endregion #region dot AggregateVectors(T.Int, builder, type => string.Format("int dot({0} arg1, {0} arg2) {{ return ", type), type => "arg1.x * arg2.x", (type, i) => string.Format(" + arg1.{0} * arg2.{0}", VectorElement(i)), type => "; }"); #endregion #region fmod builder.AppendLine("#define fmod(X, Y) (X - Y * trunc(X / Y))"); #endregion #region frac builder.AppendLine("#define frac(X) fract(X)"); #endregion #region frexp builder.AppendLine("float frexp(float x, out float e) { float absx = abs(x); e = ceil(log2(absx)); return absx * exp2(-e); }"); Vectors(T.Float, builder, "{0} frexp({0} x, out {0} e) {{ {0} absx = abs(x); e = ceil(log2(absx)); return absx * exp2(-e); }}"); //Matrices(T.Float, builder, "{0} frexp({0} x, out {0} e) {{ {0} absx = abs(x); e = ceil(log2(absx)); return absx * exp2(-e); }}"); #endregion #region GetRenderTargetSampleCount if (stage == ShaderStage.Pixel) { builder.AppendLine("#define GetRenderTargetSampleCount() gl_NumSamples"); //builder.AppendLine("uint GetRenderTargetSampleCount() { return gl_NumSamples; }"); } #endregion #region GetRenderTargetSamplePosition if (stage == ShaderStage.Pixel) { builder.AppendLine("#define GetRenderTargetSamplePosition() gl_SamplePosition "); //builder.AppendLine("uint GetRenderTargetSampleCount() { return gl_NumSamples; }"); } #endregion #region isfinite builder.AppendLine("#define isfinite(X) (!isinf(X))"); #endregion #region ldexp builder.AppendLine("float ldexp(float x, float e) { return x * exp2(e); } "); Vectors(T.Float, builder, "{0} ldexp({0} x, {0} e) {{ return x * exp2(e); }}"); //Matrices(T.Float, builder, "{0} ldexp({0} x, {0} e) {{ return x * exp2(e); }}"); #endregion #region lerp builder.AppendLine("#define lerp mix"); #endregion #region lit builder.AppendLine("float4 lit(float n_dot_l, float n_dot_h, float m) { float diffuse = max(0.0, n_dot_l); float specular; if (diffuse < 0.0) specular = 0.0; else specular = pow(n_dot_h, m); return float4(1.0, diffuse, specular, 1.0); } "); #endregion #region log10 builder.AppendLine("#define log10(X) (log2(X) / log2(10.0))"); #endregion #region modf builder.AppendLine("float modf(float x, out int ip) { float ipf; float result = modf(x, ipf); ip = int(ipf); return result; }"); Vectors(T.Float, builder, (type, size) => string.Format("{0} modf({0} x, out int{1} ip) {{ {0} ipf; {0} result = modf(x, ipf); ip = int{1}(ipf); return result; }}", type, size)); #endregion #region mul builder.AppendLine("#define mul(A, B) (A * B)"); #endregion #region noise //builder.AppendLine("#define noise noise1"); #endregion #region rsqrt builder.AppendLine("#define rsqrt inversesqrt"); #endregion #region sqrt builder.AppendLine("#define saturate(x) clamp(x, 0.0, 1.0)"); #endregion #region sincos builder.AppendLine("void sincos(float x, out float s, out float c) { s = sin(x); c = cos(x); }"); Vectors(T.Float, builder, "void sincos({0} x, out {0} s, out {0} c) {{ s = sin(x); c = cos(x); }}"); #endregion #region Textures builder.AppendLine(@" #define calculateLevelOfDetail(T, C) textureQueryLod(T, C).x #define gather(T, C) textureGather(T, C) #define gatherOffset(T, C, O) textureGatherOffset(T, C, O) #define gatherCmp(T, C, V) textureGather(T, C, V) #define gatherCmpOffset(T, C, V, O) textureGatherOffset(T, C, V, O) #define getSize(T) textureSize(T) #define BS_TEXTURE_LOAD_DIMENSION(T) BS_TEXTURE_LOAD_DIMENSION_##T #define load(T, C) BS_TEXTURE_LOAD(BS_TEXTURE_LOAD_DIMENSION(T), T, C) #define BS_TEXTURE_LOAD(D, T, C) BS_TEXTURE_LOAD_##D(T, C) #define BS_TEXTURE_LOAD_2(T, C) texelFetch(T, C.x, C.y) #define BS_TEXTURE_LOAD_3(T, C) texelFetch(T, C.xy, C.z) #define BS_TEXTURE_LOAD_4(T, C) texelFetch(T, C.xyz, C.w) #define loadOffset(T, C, O) BS_TEXTURE_LOAD_OFFSET(BS_TEXTURE_LOAD_DIMENSION(T), T, C, O) #define BS_TEXTURE_LOAD_OFFSET(D, T, C, O) BS_TEXTURE_LOAD_OFFSET_##D(T, C, O) #define BS_TEXTURE_LOAD_OFFSET_2(T, C, O) texelFetchOffset(T, C.x, C.y, O) #define BS_TEXTURE_LOAD_OFFSET_3(T, C, O) texelFetchOffset(T, C.xy, C.z, O) #define BS_TEXTURE_LOAD_OFFSET_4(T, C, O) texelFetchOffset(T, C.xyz, C.w, O) #define loadSample(T, C, S) texelFetch(T, C, S) #define sample(T, C) texture(T, C) #define sampleOffset(T, C, O) textureOffset(T, C, O) #define sampleBias(T, C, B) texture(T, C, B) #define sampleBiasOffset(T, C, B, O) textureOffset(T, C, O, B) #define BS_TEXTURE_SAMPLE_CMP_DIMENSION(T) BS_TEXTURE_SAMPLE_CMP_DIMENSION_##T #define sampleCmp(T, C, V) BS_TEXTURE_SAMPLE_CMP(BS_TEXTURE_SAMPLE_CMP_DIMENSION(T), T, C, V) #define BS_TEXTURE_SAMPLE_CMP(D, T, C, V) BS_TEXTURE_SAMPLE_CMP_##D(T, C, V) #define BS_TEXTURE_SAMPLE_CMP_1(T, C, V) uint(texture(t, float3(l, 0.0, v))) #define BS_TEXTURE_SAMPLE_CMP_2(T, C, V) uint(texture(t, float3(l, v))) #define BS_TEXTURE_SAMPLE_CMP_3(T, C, V) uint(texture(t, float4(l, v))) #define BS_TEXTURE_SAMPLE_CMP_4(T, C, V) uint(texture(t, l, v)) #define sampleCmpOffset(T, C, V, O) BS_TEXTURE_SAMPLE_CMP_OFFSET(BS_TEXTURE_SAMPLE_CMP_DIMENSION(T), T, C, V, O) #define BS_TEXTURE_SAMPLE_CMP_OFFSET(D, T, C, V, O) BS_TEXTURE_SAMPLE_CMP_OFFSET_##D(T, C, V, O) #define BS_TEXTURE_SAMPLE_CMP_OFFSET_1(T, C, V, O) uint(textureOffset(T, float3(C, 0.0, V), O))) #define BS_TEXTURE_SAMPLE_CMP_OFFSET_2(T, C, V, O) uint(textureOffset(T, float3(C, V), O)) #define BS_TEXTURE_SAMPLE_CMP_OFFSET_3(T, C, V, O) uint(textureOffset(T, float4(C, V), O)) #define sampleCmpLevelZero(T, C, V) BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO(BS_TEXTURE_SAMPLE_CMP_DIMENSION(T), T, C, V) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO(D, T, C, V) BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_##D(T, C, V) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_1(T, C, V) uint(texture(t, float3(l, 0.0, v))) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_2(T, C, V) uint(texture(t, float3(l, v))) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_3(T, C, V) uint(texture(t, float4(l, v))) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_4(T, C, V) uint(texture(t, l, v)) #define sampleCmpLevelZeroOffset(T, C, V, O) BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_OFFSET(BS_TEXTURE_SAMPLE_CMP_DIMENSION(T), T, C, V, O) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_OFFSET(D, T, C, V, O) BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_OFFSET_##D(T, C, V, O) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_OFFSET_1(T, C, V, O) uint(textureLodOffset(T, float3(C, 0.0, V), 0.0, O)) #define BS_TEXTURE_SAMPLE_CMP_LEVEL_ZERO_OFFSET_2(T, C, V, O) uint(textureLodOffset(T, float3(C, V), 0.0, O)) #define sampleGrad(T, C, X, Y) textureGrad(T, C, X, Y) #define sampleGradOffset(T, C, X, Y, O) textureGradOffset(T, C, X, Y, O) #define sampleLod(T, C, L) textureLod(T, C, L) #define sampleLodOffset(T, C, L, O) textureLodOffset(T, C, L, O) "); #endregion return builder.ToString(); }
public static MethodDefinition GetEntryPoint(this Shader shader, ShaderStage type) { return(shader.Declarations.OfType <MethodDefinition>().FirstOrDefault(f => f.Attributes.OfType <AttributeDeclaration>().Any(a => a.Name == "EntryPoint" && (string)a.Parameters[0].Value == type.ToString()))); }
static void WriteIOAndCode(StringBuilder builder, CVertexShader shader, ShaderStage outputStage) { var reflection = shader.Reflection; WriteCodeLines(builder, reflection.CodeGlobalLines); builder.AppendLine(); WriteSimpleIOBlock(builder, reflection.Input, "INPUT", "in", OutputPrefixForStage(ShaderStage.Vertex)); WriteSimpleIOBlock(builder, reflection.Output, "OUTPUT", "out", OutputPrefixForStage(outputStage)); WriteFunction(builder, "main", null, reflection.CodeMainLines, outputStage == ShaderStage.Pixel ? PositionAdjustment : null); }
private string Compile(string shaderSource, string entryPoint, ShaderStage stage, bool isOpenGLES, bool isOpenGLES3, ShaderBytecodeResult shaderBytecodeResult, string sourceFilename = null) { if (isOpenGLES && !isOpenGLES3 && 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; string shaderString = null; var generateUniformBlocks = isOpenGLES && isOpenGLES3; // null entry point for pixel shader means no pixel shader. In that case, we return a default function. if (entryPoint == null && stage == ShaderStage.Pixel && isOpenGLES) { shaderString = "out float fragmentdepth; void main(){ fragmentdepth = gl_FragCoord.z; }"; } 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(isOpenGLES, isOpenGLES3); var glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult); if (glslShader == null || shaderBytecodeResult.HasErrors) return null; // Add std140 layout foreach (var constantBuffer in glslShader.Declarations.OfType<ConstantBuffer>()) { if (isOpenGLES3) // TODO: for OpenGL too? { var layoutQualifier = constantBuffer.Qualifiers.OfType<SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier(); constantBuffer.Qualifiers |= layoutQualifier; } layoutQualifier.Layouts.Add(new LayoutKeyValue("std140")); } else { constantBuffer.Qualifiers |= new LayoutQualifier(new LayoutKeyValue("std140")); } } // Output the result var glslShaderWriter = new HlslToGlslWriter(); if (isOpenGLES) { glslShaderWriter.TrimFloatSuffix = true; glslShaderWriter.GenerateUniformBlocks = generateUniformBlocks; if (!isOpenGLES3) { foreach (var variable in glslShader.Declarations.OfType<Variable>()) { if (variable.Qualifiers.Contains(ParameterQualifier.In)) { variable.Qualifiers.Values.Remove(ParameterQualifier.In); // "in" becomes "attribute" in VS, "varying" in other stages variable.Qualifiers.Values.Add( pipelineStage == PipelineStage.Vertex ? global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Attribute : global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying); } if (variable.Qualifiers.Contains(ParameterQualifier.Out)) { variable.Qualifiers.Values.Remove(ParameterQualifier.Out); variable.Qualifiers.Values.Add(global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying); } } } } // Write shader glslShaderWriter.Visit(glslShader); 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(); } if ((!isOpenGLES || isOpenGLES3) && pipelineStage == PipelineStage.Pixel && renderTargetCount > 0) { // TODO: identifiers starting with "gl_" should be reserved. Compilers usually accept them but it may should be prevented. glslShaderCode .AppendLine("#define gl_FragData _glesFragData") .AppendLine("out vec4 gl_FragData[" + renderTargetCount + "];") .AppendLine(); } glslShaderCode.Append(shaderString); var realShaderSource = glslShaderCode.ToString(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP // optimize shader try { var optShaderSource = RunOptimizer(shaderBytecodeResult, realShaderSource, isOpenGLES, isOpenGLES3, 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; }
public VertexColorMaterialSlot(int slotId, string displayName, string shaderOutputName, ShaderStage shaderStage = ShaderStage.Dynamic, bool hidden = false) : base(slotId, displayName, shaderOutputName, SlotType.Input, Vector3.zero, shaderStage, hidden) { }
static void WriteLayout(StringBuilder builder, CVertexShader shader, ShaderStage outputStage) { }
private Shader(GraphicsDevice device, ShaderStage shaderStage, byte[] shaderBytecode) : base(device) { throw new NotImplementedException(); }
internal Shader(GraphicsDevice device, BinaryReader reader) { GraphicsDevice = device; var isVertexShader = reader.ReadBoolean(); Stage = isVertexShader ? ShaderStage.Vertex : ShaderStage.Pixel; var shaderLength = reader.ReadInt32(); var shaderBytecode = reader.ReadBytes(shaderLength); var samplerCount = (int)reader.ReadByte(); Samplers = new SamplerInfo[samplerCount]; for (var s = 0; s < samplerCount; s++) { Samplers[s].type = (SamplerType)reader.ReadByte(); Samplers[s].textureSlot = reader.ReadByte(); Samplers[s].samplerSlot = reader.ReadByte(); if (reader.ReadBoolean()) { Samplers[s].state = new SamplerState(); Samplers[s].state.AddressU = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressV = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressW = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.Filter = (TextureFilter)reader.ReadByte(); Samplers[s].state.MaxAnisotropy = reader.ReadInt32(); Samplers[s].state.MaxMipLevel = reader.ReadInt32(); Samplers[s].state.MipMapLevelOfDetailBias = reader.ReadSingle(); } #if OPENGL Samplers[s].name = reader.ReadString(); #else Samplers[s].name = null; #endif Samplers[s].parameter = reader.ReadByte(); } var cbufferCount = (int)reader.ReadByte(); CBuffers = new int[cbufferCount]; for (var c = 0; c < cbufferCount; c++) CBuffers[c] = reader.ReadByte(); #if DIRECTX _shaderBytecode = shaderBytecode; // We need the bytecode later for allocating the // input layout from the vertex declaration. Bytecode = shaderBytecode; HashKey = MonoGame.Utilities.Hash.ComputeHash(Bytecode); if (isVertexShader) CreateVertexShader(); else CreatePixelShader(); #endif // DIRECTX #if OPENGL _glslCode = System.Text.Encoding.ASCII.GetString(shaderBytecode); HashKey = MonoGame.Utilities.Hash.ComputeHash(shaderBytecode); var attributeCount = (int)reader.ReadByte(); _attributes = new Attribute[attributeCount]; for (var a = 0; a < attributeCount; a++) { _attributes[a].name = reader.ReadString(); _attributes[a].usage = (VertexElementUsage)reader.ReadByte(); _attributes[a].index = reader.ReadByte(); _attributes[a].format = reader.ReadInt16(); } #endif // OPENGL }
public void PushConstant <T>(GraphicsPipeline pipelineLayout, ShaderStage stageFlags, T data, uint offset = 0) where T : unmanaged { vkCmdPushConstants(handle, pipelineLayout._pipelineLayout, stageFlags.StageToVkShaderStageFlags(), offset, (uint)Interop.SizeOf <T>(), (void *)&data /*Interop.AllocToPointer<T>(ref data)*/); }
/// <summary> /// Sets a constant buffer to the shader pipeline. /// </summary> /// <param name="stage">The shader stage.</param> /// <param name="slot">The binding slot.</param> /// <param name="buffer">The constant buffer to set.</param> internal void SetConstantBuffer(ShaderStage stage, int slot, Buffer buffer) { if (stage == ShaderStage.None) throw new ArgumentException("Cannot use Stage.None", "stage"); int stageIndex = (int)stage - 1; int slotIndex = stageIndex * ConstantBufferCount + slot; if (constantBuffers[slotIndex] != buffer) { constantBuffers[slotIndex] = buffer; shaderStages[stageIndex].SetConstantBuffer(slot, buffer != null ? buffer.NativeBuffer : null); } }
public UVMaterialSlot(int slotId, string displayName, string shaderOutputName, UVChannel channel, ShaderStage shaderStage = ShaderStage.Dynamic, bool hidden = false) : base(slotId, displayName, shaderOutputName, SlotType.Input, Vector2.zero, shaderStage, hidden) { this.channel = channel; }
public PositionMaterialSlot(int slotId, string displayName, string shaderOutputName, CoordinateSpace space, ShaderStage shaderStage = ShaderStage.Dynamic, bool hidden = false) : base(slotId, displayName, shaderOutputName, space, shaderStage, hidden) { }
public void UpdateRenderScale(ShaderStage stage, ReadOnlySpan <float> scales, int textureCount, int imageCount) { _renderer.New <UpdateRenderScaleCommand>().Set(stage, _renderer.CopySpan(scales.Slice(0, textureCount + imageCount)), textureCount, imageCount); _renderer.QueueCommand(); }
private string Compile(string shaderSource, string entryPoint, ShaderStage stage, bool isOpenGLES, bool isOpenGLES3, ShaderBytecodeResult shaderBytecodeResult, string sourceFilename = null) { if (isOpenGLES && !isOpenGLES3 && 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); } string shaderString = null; var generateUniformBlocks = isOpenGLES && isOpenGLES3; // null entry point for pixel shader means no pixel shader. In that case, we return a default function. if (entryPoint == null && stage == ShaderStage.Pixel && isOpenGLES) { shaderString = "void main(){}"; } 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(isOpenGLES, isOpenGLES3); var glslShader = glslConvertor.Convert(shaderSource, entryPoint, pipelineStage, sourceFilename, shaderBytecodeResult); if (glslShader == null || shaderBytecodeResult.HasErrors) { return(null); } // Add std140 layout foreach (var constantBuffer in glslShader.Declarations.OfType <ConstantBuffer>()) { if (isOpenGLES3) // TODO: for OpenGL too? { var layoutQualifier = constantBuffer.Qualifiers.OfType <SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new SiliconStudio.Shaders.Ast.Glsl.LayoutQualifier(); constantBuffer.Qualifiers |= layoutQualifier; } layoutQualifier.Layouts.Add(new LayoutKeyValue("std140")); } else { constantBuffer.Qualifiers |= new LayoutQualifier(new LayoutKeyValue("std140")); } } // Output the result var glslShaderWriter = new HlslToGlslWriter(); if (isOpenGLES) { glslShaderWriter.TrimFloatSuffix = true; glslShaderWriter.GenerateUniformBlocks = generateUniformBlocks; if (!isOpenGLES3) { foreach (var variable in glslShader.Declarations.OfType <Variable>()) { if (variable.Qualifiers.Contains(ParameterQualifier.In)) { variable.Qualifiers.Values.Remove(ParameterQualifier.In); // "in" becomes "attribute" in VS, "varying" in other stages variable.Qualifiers.Values.Add( pipelineStage == PipelineStage.Vertex ? global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Attribute : global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying); } if (variable.Qualifiers.Contains(ParameterQualifier.Out)) { variable.Qualifiers.Values.Remove(ParameterQualifier.Out); variable.Qualifiers.Values.Add(global::SiliconStudio.Shaders.Ast.Glsl.ParameterQualifier.Varying); } } } } // Write shader glslShaderWriter.Visit(glslShader); 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 (generateUniformBlocks) // TODO: is it really needed? It produces only a warning. { glslShaderCode .AppendLine("#extension GL_ARB_gpu_shader5 : enable") .AppendLine(); } if (pipelineStage == PipelineStage.Pixel) { glslShaderCode .AppendLine("precision highp float;") .AppendLine(); } } else { glslShaderCode .AppendLine("#version 420") .AppendLine(); } if ((!isOpenGLES || isOpenGLES3) && pipelineStage == PipelineStage.Pixel && renderTargetCount > 0) { // TODO: identifiers starting with "gl_" should be reserved. Compilers usually accept them but it may should be prevented. glslShaderCode .AppendLine("out vec4 gl_FragData[" + renderTargetCount + "];") .AppendLine(); } glslShaderCode.Append(shaderString); var realShaderSource = glslShaderCode.ToString(); // optimize shader var optShaderSource = RunOptimizer(realShaderSource, isOpenGLES, isOpenGLES3, pipelineStage == PipelineStage.Vertex); if (!String.IsNullOrEmpty(optShaderSource)) { realShaderSource = optShaderSource; } return(realShaderSource); }
internal Shader(GraphicsDevice device, BinaryReader reader) { GraphicsDevice = device; var isVertexShader = reader.ReadBoolean(); Stage = isVertexShader ? ShaderStage.Vertex : ShaderStage.Pixel; var shaderLength = reader.ReadInt32(); var shaderBytecode = reader.ReadBytes(shaderLength); var samplerCount = (int)reader.ReadByte(); Samplers = new SamplerInfo[samplerCount]; for (var s = 0; s < samplerCount; s++) { Samplers[s].type = (SamplerType)reader.ReadByte(); Samplers[s].textureSlot = reader.ReadByte(); Samplers[s].samplerSlot = reader.ReadByte(); if (reader.ReadBoolean()) { Samplers[s].state = new SamplerState(); Samplers[s].state.AddressU = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressV = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.AddressW = (TextureAddressMode)reader.ReadByte(); Samplers[s].state.Filter = (TextureFilter)reader.ReadByte(); Samplers[s].state.MaxAnisotropy = reader.ReadInt32(); Samplers[s].state.MaxMipLevel = reader.ReadInt32(); Samplers[s].state.MipMapLevelOfDetailBias = reader.ReadSingle(); } #if OPENGL Samplers[s].name = reader.ReadString(); #else Samplers[s].name = null; #endif Samplers[s].parameter = reader.ReadByte(); } var cbufferCount = (int)reader.ReadByte(); CBuffers = new int[cbufferCount]; for (var c = 0; c < cbufferCount; c++) { CBuffers[c] = reader.ReadByte(); } #if DIRECTX _shaderBytecode = shaderBytecode; // We need the bytecode later for allocating the // input layout from the vertex declaration. Bytecode = shaderBytecode; HashKey = MonoGame.Utilities.Hash.ComputeHash(Bytecode); if (isVertexShader) { CreateVertexShader(); } else { CreatePixelShader(); } #endif // DIRECTX #if OPENGL _glslCode = System.Text.Encoding.ASCII.GetString(shaderBytecode); HashKey = MonoGame.Utilities.Hash.ComputeHash(shaderBytecode); var attributeCount = (int)reader.ReadByte(); _attributes = new Attribute[attributeCount]; for (var a = 0; a < attributeCount; a++) { _attributes[a].name = reader.ReadString(); _attributes[a].usage = (VertexElementUsage)reader.ReadByte(); _attributes[a].index = reader.ReadByte(); _attributes[a].format = reader.ReadInt16(); } #endif // OPENGL }
/// <summary> /// Sets a shader resource view to the shader pipeline. /// </summary> /// <param name="stage">The shader stage.</param> /// <param name="slot">The binding slot.</param> /// <param name="shaderResourceView">The shader resource view.</param> internal void SetShaderResourceView(ShaderStage stage, int slot, GraphicsResource shaderResourceView) { shaderStages[(int)stage - 1].SetShaderResource(slot, shaderResourceView != null ? shaderResourceView.NativeShaderResourceView : null); }
public static string GetOutAttributeName(AstOperand attr, ShaderStage stage) { return(GetAttributeName(attr, stage, isOutAttr: true)); }
public BlockFieldDescriptor(string tag, string referenceName, string displayName, string define, IControl control, ShaderStage shaderStage, bool isHidden = false, bool isUnknown = false) : base(tag, referenceName, define) { this.displayName = displayName; this.control = control; this.shaderStage = shaderStage; this.isHidden = isHidden; this.isUnknown = isUnknown; }
public static string GetAttributeName(AstOperand attr, ShaderStage stage, bool isOutAttr = false, string indexExpr = "0") { int value = attr.Value; string swzMask = GetSwizzleMask((value >> 2) & 3); if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd) { value -= AttributeConsts.UserAttributeBase; string prefix = isOutAttr ? DefaultNames.OAttributePrefix : DefaultNames.IAttributePrefix; string name = $"{prefix}{(value >> 4)}"; if (stage == ShaderStage.Geometry && !isOutAttr) { name += $"[{indexExpr}]"; } name += "." + swzMask; return(name); } else { if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd) { value -= AttributeConsts.FragmentOutputColorBase; return($"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}"); } else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr)) { // TODO: There must be a better way to handle this... if (stage == ShaderStage.Fragment) { switch (value & ~3) { case AttributeConsts.PositionX: return("gl_FragCoord.x"); case AttributeConsts.PositionY: return("gl_FragCoord.y"); case AttributeConsts.PositionZ: return("gl_FragCoord.z"); case AttributeConsts.PositionW: return("1.0"); } } string name = builtInAttr.Name; if (stage == ShaderStage.Geometry && !isOutAttr) { name = $"gl_in[{indexExpr}].{name}"; } return(name); } } // TODO: Warn about unknown built-in attribute. return(isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0"); }
/// <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(resourceId); int uniformBlockCount; GL.GetProgram(resourceId, PdxActiveUniformBlocks, out uniformBlockCount); for (int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { // TODO: get previous name to find te actual constant buffer in the reflexion #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES const int sbCapacity = 128; int length; var sb = new StringBuilder(sbCapacity); GL.GetActiveUniformBlockName(resourceId, uniformBlockIndex, sbCapacity, out length, sb); var constantBufferName = sb.ToString(); #else var constantBufferName = GL.GetActiveUniformBlockName(resourceId, uniformBlockIndex); #endif var constantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == constantBufferName); if (constantBufferDescriptionIndex == -1) { reflectionResult.Error("Unable to find the constant buffer description [{0}]", constantBufferName); return; } var constantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.RawName == constantBufferName); if (constantBufferIndex == -1) { reflectionResult.Error("Unable to find the constant buffer [{0}]", constantBufferName); return; } var constantBufferDescription = effectReflection.ConstantBuffers[constantBufferDescriptionIndex]; var constantBuffer = effectReflection.ResourceBindings[constantBufferIndex]; GL.GetActiveUniformBlock(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockDataSize, out constantBufferDescription.Size); int uniformCount; GL.GetActiveUniformBlock(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniforms, out uniformCount); // set the binding GL.UniformBlockBinding(resourceId, 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(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniformIndices, uniformIndices); GL.GetActiveUniforms(resourceId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformOffset, uniformOffsets); GL.GetActiveUniforms(resourceId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformType, uniformTypes); for (int uniformIndex = 0; uniformIndex < uniformIndices.Length; ++uniformIndex) { #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES int size; ActiveUniformType aut; GL.GetActiveUniform(resourceId, uniformIndices[uniformIndex], sbCapacity, out length, out size, out aut, sb); uniformNames[uniformIndex] = sb.ToString(); #else uniformNames[uniformIndex] = GL.GetActiveUniformName(resourceId, 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].Param.RawName == variableIndexGroup.Name) { variableIndex = tentativeIndex; break; } } if (variableIndex == -1) { reflectionResult.Error("Unable to find uniform [{0}] in constant buffer [{1}]", variableIndexGroup.Name, constantBufferName); continue; } var variable = constantBufferDescription.Members[variableIndex]; variable.Param.Type = GetTypeFromActiveUniformType(variableIndexGroup.Type); variable.Offset = variableIndexGroup.Offset; variable.Size = variableIndexGroup.NextOffset - variableIndexGroup.Offset; constantBufferDescription.Members[variableIndex] = variable; } constantBufferDescription.Stage = stage; constantBufferDescription.Type = ConstantBufferType.ConstantBuffer; constantBuffer.SlotCount = 1; // constant buffers are not arrays constantBuffer.SlotStart = uniformBlockIndex; constantBuffer.Stage = stage; // store the new values effectReflection.ConstantBuffers[constantBufferDescriptionIndex] = constantBufferDescription; effectReflection.ResourceBindings[constantBufferIndex] = constantBuffer; } //#endif // 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 EffectParameterResourceData { Param = { RawName = "NoSampler", KeyName = "NoSampler", Class = EffectParameterClass.Sampler }, SlotStart = -1 }; effectBytecode.Reflection.ResourceBindings.Add(noSampler); bool usingSamplerNoSampler = false; int activeUniformCount; GL.GetProgram(resourceId, ProgramParameter.ActiveUniforms, out activeUniformCount); #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES var uniformTypes = new int[activeUniformCount]; GL.GetActiveUniforms(resourceId, activeUniformCount, Enumerable.Range(0, activeUniformCount).ToArray(), ActiveUniformParameter.UniformType, uniformTypes); #endif #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES if (GraphicsDevice.IsOpenGLES2) { // Register global "fake" cbuffer //var constantBuffer = new ShaderReflectionConstantBuffer // { // Name = "$Globals", // Variables = new List<ShaderReflectionVariable>(), // Type = ConstantBufferType.ConstantBuffer // }; //shaderReflection.ConstantBuffers.Add(constantBuffer); //shaderReflection.BoundResources.Add(new InputBindingDescription { BindPoint = 0, BindCount = 1, Name = constantBuffer.Name, Type = ShaderInputType.ConstantBuffer }); // reset the size of the constant buffers foreach (var constantBuffer in effectReflection.ConstantBuffers) { constantBuffer.Size = 0; } // set the state of the constant buffers foreach (var constantBuffer in effectReflection.ConstantBuffers) { constantBuffer.Stage = stage; } for (int i = 0; i < effectReflection.ResourceBindings.Count; i++) { if (effectReflection.ResourceBindings[i].Param.Class != EffectParameterClass.ConstantBuffer) { continue; } var globalConstantBufferCopy = effectReflection.ResourceBindings[i]; globalConstantBufferCopy.Stage = stage; effectReflection.ResourceBindings[i] = globalConstantBufferCopy; } //Create a Globals constant buffer if necessary var globalConstantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == "Globals"); var globalConstantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.RawName == "Globals"); if (globalConstantBufferDescriptionIndex == -1 && globalConstantBufferIndex == -1) { var newConstantBufferDescription = new ShaderConstantBufferDescription { Name = "Globals", Stage = stage, Type = ConstantBufferType.ConstantBuffer, Size = 0, Members = new EffectParameterValueData[0], }; var newConstantBuffer = new EffectParameterResourceData { Stage = stage, SlotStart = 0, SlotCount = 1, Param = { RawName = "Globals", KeyName = "Globals", Type = EffectParameterType.ConstantBuffer, Class = EffectParameterClass.ConstantBuffer } }; effectReflection.ConstantBuffers.Add(newConstantBufferDescription); effectReflection.ResourceBindings.Add(newConstantBuffer); globalConstantBufferDescriptionIndex = effectReflection.ConstantBuffers.Count - 1; globalConstantBufferIndex = effectReflection.ResourceBindings.Count - 1; } // Merge all the variables in the Globals constant buffer if (globalConstantBufferDescriptionIndex != -1 && globalConstantBufferIndex != -1) { var globalConstantBufferDescription = effectReflection.ConstantBuffers[globalConstantBufferDescriptionIndex]; for (int cstDescrIndex = 0; cstDescrIndex < effectReflection.ConstantBuffers.Count; ++cstDescrIndex) { if (cstDescrIndex == globalConstantBufferDescriptionIndex) { continue; } var currentConstantBufferDescription = effectReflection.ConstantBuffers[cstDescrIndex]; globalConstantBufferDescription.Members = ArrayExtensions.Concat( globalConstantBufferDescription.Members, currentConstantBufferDescription.Members); effectReflection.ResourceBindings.RemoveAll(x => x.Param.RawName == currentConstantBufferDescription.Name); } // only keep the active uniforms globalConstantBufferDescription.Members = globalConstantBufferDescription.Members.Where(x => GL.GetUniformLocation(resourceId, #if SILICONSTUDIO_PLATFORM_ANDROID new StringBuilder(x.Param.RawName) #else x.Param.RawName #endif ) >= 0).ToArray(); // remove all the constant buffers and their resource bindings except the Globals one effectReflection.ConstantBuffers.Clear(); effectReflection.ConstantBuffers.Add(globalConstantBufferDescription); } else if (globalConstantBufferDescriptionIndex != -1 && globalConstantBufferIndex == -1) { reflectionResult.Error("Globals constant buffer has a description and no resource binding"); } else if (globalConstantBufferDescriptionIndex == -1 && globalConstantBufferIndex != -1) { reflectionResult.Error("Globals constant buffer has a description and no resource binding"); } } #endif int textureUnitCount = 0; for (int activeUniformIndex = 0; activeUniformIndex < activeUniformCount; ++activeUniformIndex) { #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES var uniformType = (ActiveUniformType)uniformTypes[activeUniformIndex]; var uniformName = GL.GetActiveUniformName(resourceId, activeUniformIndex); #else ActiveUniformType uniformType; int uniformCount; var uniformName = GL.GetActiveUniform(resourceId, activeUniformIndex, out uniformCount, out uniformType); //int uniformSize; //GL.GetActiveUniform(resourceId, activeUniformIndex, out uniformSize, ActiveUniformType.Float); #endif switch (uniformType) { #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES case ActiveUniformType.Bool: case ActiveUniformType.Int: AddUniform(effectReflection, sizeof(int) * 1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec2: case ActiveUniformType.IntVec2: AddUniform(effectReflection, sizeof(int) * 2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec3: case ActiveUniformType.IntVec3: AddUniform(effectReflection, sizeof(int) * 3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec4: case ActiveUniformType.IntVec4: AddUniform(effectReflection, sizeof(int) * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.Float: AddUniform(effectReflection, sizeof(float) * 1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec2: AddUniform(effectReflection, sizeof(float) * 2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec3: AddUniform(effectReflection, sizeof(float) * 3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec4: AddUniform(effectReflection, sizeof(float) * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat4: AddUniform(effectReflection, sizeof(float) * 4 * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat2: case ActiveUniformType.FloatMat3: throw new NotImplementedException(); #endif #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES case ActiveUniformType.Sampler1D: #endif case ActiveUniformType.Sampler2D: case ActiveUniformType.Sampler3D: // TODO: remove Texture3D that is not available in OpenGL ES 2 case ActiveUniformType.SamplerCube: #if SILICONSTUDIO_PLATFORM_ANDROID var uniformIndex = GL.GetUniformLocation(resourceId, new StringBuilder(uniformName)); #else var uniformIndex = GL.GetUniformLocation(resourceId, uniformName); #endif // 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.Param.RawName == textureName); samplerReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.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 [{0}]", 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.Param.Type = GetTypeFromActiveUniformType(uniformType); textureReflection.SlotStart = textureUnitCount; textureReflection.SlotCount = 1; // TODO: texture arrays textureReflection.Param.Class = EffectParameterClass.ShaderResourceView; samplerReflection.Stage = stage; samplerReflection.SlotStart = textureUnitCount; samplerReflection.SlotCount = 1; // TODO: texture arrays samplerReflection.Param.Class = EffectParameterClass.Sampler; 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); } 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) { 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) { // 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); // 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(); 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, ElementType = x.ElementType.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 <Stride.Core.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new Stride.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 <Stride.Core.Shaders.Ast.Glsl.LayoutQualifier>().FirstOrDefault(); if (layoutQualifier == null) { layoutQualifier = new Stride.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); }
public Shader CreateShaderFromFile(ShaderStage shaderStage, string filePath, VertexType vertexType, IEnumerable <(string, string)> macros)
private static void MarkResourceBindingAsUsed(EffectReflection reflection, int resourceBindingIndex, ShaderStage stage) { var resourceBinding = reflection.ResourceBindings[resourceBindingIndex]; if (resourceBinding.Stage == ShaderStage.None) { resourceBinding.Stage = stage; reflection.ResourceBindings[resourceBindingIndex] = resourceBinding; } }
VertexShader CreateNative(ShaderStage outputStage) { var text = GenerateText<CVertexShader, ShaderStage>(outputStage, WriteLayout, WriteIOAndCode); VertexShader glShader; string errors; if (!VertexShader.TryCompile(text, out glShader, out errors)) throw new Exception("Failed to compile a shader.\r\n\r\nShader Text:\r\n\r\n" + text + "\r\n\r\nErrors:\r\n\r\n" + errors); return glShader; }
/// <summary> /// Converts the hlsl code into glsl and stores the result as plain text /// </summary> /// <param name="shaderSource">the hlsl shader</param> /// <param name="entryPoint">the entrypoint function name</param> /// <param name="stage">the shader pipeline stage</param> /// <param name="effectParameters"></param> /// <param name="reflection">the reflection gathered from the hlsl analysis</param> /// <param name="sourceFilename">the name of the source file</param> /// <returns></returns> public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var shaderBytecodeResult = new ShaderBytecodeResult(); byte[] rawData; var inputAttributeNames = new Dictionary <int, string>(); var resourceBindings = new Dictionary <string, int>(); GlslShaderPlatform shaderPlatform; int shaderVersion; switch (effectParameters.Platform) { case GraphicsPlatform.OpenGL: shaderPlatform = GlslShaderPlatform.OpenGL; shaderVersion = 410; break; case GraphicsPlatform.OpenGLES: shaderPlatform = GlslShaderPlatform.OpenGLES; shaderVersion = 300; break; case GraphicsPlatform.Vulkan: shaderPlatform = GlslShaderPlatform.Vulkan; shaderVersion = 450; break; default: throw new ArgumentOutOfRangeException("effectParameters.Platform"); } var shader = Compile(shaderSource, entryPoint, stage, shaderPlatform, shaderVersion, shaderBytecodeResult, reflection, inputAttributeNames, resourceBindings, sourceFilename); if (shader == null) { return(shaderBytecodeResult); } if (effectParameters.Platform == GraphicsPlatform.OpenGLES) // TODO: Add check to run on android only. The current version breaks OpenGL ES on windows. { //TODO: Remove this ugly hack! if (shaderSource.Contains($"Texture2D StrideInternal_TextureExt0") && shader.Contains("uniform sampler2D")) { if (shaderPlatform != GlslShaderPlatform.OpenGLES || shaderVersion != 300) { throw new Exception("Invalid GLES platform or version: require OpenGLES 300"); } shader = shader.Replace("uniform sampler2D", "uniform samplerExternalOES"); shader = shader.Replace("#version 300 es", "#version 300 es\n#extension GL_OES_EGL_image_external_essl3 : require"); } } if (effectParameters.Platform == GraphicsPlatform.Vulkan) { string inputFileExtension; switch (stage) { case ShaderStage.Vertex: inputFileExtension = ".vert"; break; case ShaderStage.Pixel: inputFileExtension = ".frag"; break; case ShaderStage.Geometry: inputFileExtension = ".geom"; break; case ShaderStage.Domain: inputFileExtension = ".tese"; break; case ShaderStage.Hull: inputFileExtension = ".tesc"; break; case ShaderStage.Compute: inputFileExtension = ".comp"; break; default: shaderBytecodeResult.Error("Unknown shader profile"); return(shaderBytecodeResult); } var inputFileName = Path.ChangeExtension(Path.GetTempFileName(), inputFileExtension); var outputFileName = Path.ChangeExtension(inputFileName, ".spv"); // Write shader source to disk File.WriteAllBytes(inputFileName, Encoding.ASCII.GetBytes(shader)); // Run shader compiler string filename; switch (Platform.Type) { case PlatformType.Windows: case PlatformType.UWP: filename = @"win-x64\glslangValidator.exe"; break; case PlatformType.Linux: filename = @"linux-x64\glslangValidator.bin"; break; case PlatformType.macOS: filename = @"osx-x64\glslangValidator.bin"; break; default: throw new PlatformNotSupportedException(); } ShellHelper.RunProcessAndRedirectToLogger(filename, $"-V -o {outputFileName} {inputFileName}", null, shaderBytecodeResult); if (!File.Exists(outputFileName)) { shaderBytecodeResult.Error("Failed to generate SPIR-V from GLSL"); return(shaderBytecodeResult); } // Read compiled shader var shaderBytecodes = new ShaderInputBytecode { InputAttributeNames = inputAttributeNames, ResourceBindings = resourceBindings, Data = File.ReadAllBytes(outputFileName), }; using (var stream = new MemoryStream()) { BinarySerialization.Write(stream, shaderBytecodes); rawData = stream.ToArray(); } // Cleanup temp files File.Delete(inputFileName); File.Delete(outputFileName); } else { // store string on OpenGL platforms rawData = Encoding.UTF8.GetBytes(shader); } var bytecodeId = ObjectId.FromBytes(rawData); var bytecode = new ShaderBytecode(bytecodeId, rawData); bytecode.Stage = stage; shaderBytecodeResult.Bytecode = bytecode; return(shaderBytecodeResult); }
protected MaterialSlot(int slotId, string displayName, string shaderOutputName, SlotType slotType, int priority, ShaderStage shaderStage = ShaderStage.Dynamic, bool hidden = false) { m_Id = slotId; m_DisplayName = displayName; m_SlotType = slotType; m_Priority = priority; m_Hidden = hidden; m_ShaderOutputName = shaderOutputName; this.shaderStage = shaderStage; }
internal ConstantBufferCollection(ShaderStage stage, int maxBuffers) { _stage = stage; _buffers = new ConstantBuffer[maxBuffers]; _valid = 0; }
public static MaterialSlot CreateMaterialSlot(SlotValueType type, int slotId, string displayName, string shaderOutputName, SlotType slotType, Vector4 defaultValue, ShaderStage shaderStage = ShaderStage.Dynamic, bool hidden = false) { switch (type) { case SlotValueType.SamplerState: return(new SamplerStateMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.DynamicMatrix: return(new DynamicMatrixMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Matrix4: return(new Matrix4MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Matrix3: return(new Matrix3MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Matrix2: return(new Matrix2MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Texture2D: return(slotType == SlotType.Input ? new Texture2DInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStage, hidden) : new Texture2DMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Cubemap: return(slotType == SlotType.Input ? new CubemapInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStage, hidden) : new CubemapMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.Gradient: return(slotType == SlotType.Input ? new GradientInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStage, hidden) : new GradientMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStage, hidden)); case SlotValueType.DynamicVector: return(new DynamicVectorMaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStage, hidden)); case SlotValueType.Vector4: return(new Vector4MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStage, hidden: hidden)); case SlotValueType.Vector3: return(new Vector3MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStage, hidden: hidden)); case SlotValueType.Vector2: return(new Vector2MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStage, hidden: hidden)); case SlotValueType.Vector1: return(new Vector1MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue.x, shaderStage, hidden: hidden)); case SlotValueType.Dynamic: return(new DynamicValueMaterialSlot(slotId, displayName, shaderOutputName, slotType, new Matrix4x4(defaultValue, Vector4.zero, Vector4.zero, Vector4.zero), shaderStage, hidden)); case SlotValueType.Boolean: return(new BooleanMaterialSlot(slotId, displayName, shaderOutputName, slotType, false, shaderStage, hidden)); } throw new ArgumentOutOfRangeException("type", type, null); }
public ShaderGeneratorResult GenerateSharedVertexShader(VertexType vertexType, ShaderStage entryPoint) { return(null); }
private void PlatformConstruct(ShaderStage stage, byte[] shaderBytecode) { GlslCode = System.Text.Encoding.ASCII.GetString(shaderBytecode); HashKey = HashHelper.ComputeHash(shaderBytecode); }
public bool IsMethodSharedInEntryPoint(ShaderStage entryPoint, int method_index) { return(method_index == 1); }
public ShaderBytecodeResult Compile(string shaderSource, string entryPoint, ShaderStage stage, EffectCompilerParameters effectParameters, EffectReflection reflection, string sourceFilename = null) { var isDebug = effectParameters.Debug; var optimLevel = effectParameters.OptimizationLevel; var profile = effectParameters.Profile; var shaderModel = ShaderStageToString(stage) + "_" + ShaderProfileFromGraphicsProfile(profile); var shaderFlags = ShaderFlags.None; if (isDebug) { shaderFlags = ShaderFlags.Debug; } switch (optimLevel) { case 0: shaderFlags |= ShaderFlags.OptimizationLevel0; break; case 1: shaderFlags |= ShaderFlags.OptimizationLevel1; break; case 2: shaderFlags |= ShaderFlags.OptimizationLevel2; break; case 3: shaderFlags |= ShaderFlags.OptimizationLevel3; break; } SharpDX.Configuration.ThrowOnShaderCompileError = false; // Compile using D3DCompiler var compilationResult = SharpDX.D3DCompiler.ShaderBytecode.Compile(shaderSource, entryPoint, shaderModel, shaderFlags, EffectFlags.None, null, null, sourceFilename); var byteCodeResult = new ShaderBytecodeResult(); if (compilationResult.HasErrors || compilationResult.Bytecode == null) { // Log compilation errors byteCodeResult.Error(compilationResult.Message); } else { // TODO: Make this optional try { byteCodeResult.DisassembleText = compilationResult.Bytecode.Disassemble(); } catch (SharpDXException) { } // As effect bytecode binary can changed when having debug infos (with d3dcompiler_47), we are calculating a bytecodeId on the stripped version var rawData = compilationResult.Bytecode.Strip(StripFlags.CompilerStripDebugInformation | StripFlags.CompilerStripReflectionData); var bytecodeId = ObjectId.FromBytes(rawData); byteCodeResult.Bytecode = new ShaderBytecode(bytecodeId, compilationResult.Bytecode.Data) { Stage = stage }; // If compilation succeed, then we can update reflection. UpdateReflection(byteCodeResult.Bytecode, reflection, byteCodeResult); if (!string.IsNullOrEmpty(compilationResult.Message)) { byteCodeResult.Warning(compilationResult.Message); } } return(byteCodeResult); }
private static string ShaderStageToString(ShaderStage stage) { string shaderStageText; switch (stage) { case ShaderStage.Compute: shaderStageText = "cs"; break; case ShaderStage.Vertex: shaderStageText = "vs"; break; case ShaderStage.Hull: shaderStageText = "hs"; break; case ShaderStage.Domain: shaderStageText = "ds"; break; case ShaderStage.Geometry: shaderStageText = "gs"; break; case ShaderStage.Pixel: shaderStageText = "ps"; break; default: throw new ArgumentException("Stage not supported", "stage"); } return shaderStageText; }
/// <summary> /// Sets a sampler state to the shader pipeline. /// </summary> /// <param name="stage">The shader stage.</param> /// <param name="slot">The binding slot.</param> /// <param name="samplerState">The sampler state to set.</param> internal void SetSamplerState(ShaderStage stage, int slot, SamplerState samplerState) { if (stage == ShaderStage.None) throw new ArgumentException("Cannot use Stage.None", "stage"); int stageIndex = (int)stage - 1; int slotIndex = stageIndex * SamplerStateCount + slot; if (samplerStates[slotIndex] != samplerState) { samplerStates[slotIndex] = samplerState; shaderStages[stageIndex].SetSampler(slot, samplerState != null ? (SharpDX.Direct3D11.SamplerState)samplerState.NativeDeviceChild : null); } }
/// <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 SILICONSTUDIO_XENKO_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 [{0}]", constantBufferName); return; } var constantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferName); if (constantBufferIndex == -1) { reflectionResult.Error("Unable to find the constant buffer [{0}]", 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 SILICONSTUDIO_XENKO_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 [{0}] in constant buffer [{1}]", variableIndexGroup.Name, 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 !SILICONSTUDIO_XENKO_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 !SILICONSTUDIO_XENKO_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 #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES // Process uniforms if (GraphicsDevice.IsOpenGLES2) { switch (uniformType) { case ActiveUniformType.Bool: case ActiveUniformType.Int: AddUniform(effectReflection, validConstantBuffers, sizeof(int)*1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec2: case ActiveUniformType.IntVec2: AddUniform(effectReflection, validConstantBuffers, sizeof(int)*2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec3: case ActiveUniformType.IntVec3: AddUniform(effectReflection, validConstantBuffers, sizeof(int)*3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec4: case ActiveUniformType.IntVec4: AddUniform(effectReflection, validConstantBuffers, sizeof(int)*4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.Float: AddUniform(effectReflection, validConstantBuffers, sizeof(float)*1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec2: AddUniform(effectReflection, validConstantBuffers, sizeof(float)*2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec3: AddUniform(effectReflection, validConstantBuffers, sizeof(float)*3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec4: AddUniform(effectReflection, validConstantBuffers, sizeof(float)*4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat4: AddUniform(effectReflection, validConstantBuffers, sizeof(float)*4*4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat2: case ActiveUniformType.FloatMat3: throw new NotImplementedException(); } } #endif switch (uniformType) { #if !SILICONSTUDIO_XENKO_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 [{0}]", 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); }
/// <summary> /// Sets an unordered access view to the shader pipeline. /// </summary> /// <param name="stage">The stage.</param> /// <param name="slot">The slot.</param> /// <param name="unorderedAccessView">The unordered access view.</param> /// <exception cref="System.ArgumentException">Invalid stage.;stage</exception> internal void SetUnorderedAccessView(ShaderStage stage, int slot, GraphicsResource unorderedAccessView) { if (stage != ShaderStage.Compute) throw new ArgumentException("Invalid stage.", "stage"); NativeDeviceContext.ComputeShader.SetUnorderedAccessView(slot, unorderedAccessView != null ? unorderedAccessView.NativeUnorderedAccessView : null); }
public void SetStorageBuffer(int index, ShaderStage stage, BufferRange buffer) { SetBuffer(index, stage, buffer, isStorage: true); }
public static bool HasFlag(ShaderStage option, ShaderStage flag) { return((option & flag) != 0); }
/// <summary> /// Translates the binary Maxwell shader code to something that the host API accepts. /// </summary> /// <remarks> /// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader. /// </remarks> /// <param name="state">Current GPU state</param> /// <param name="flags">Flags that controls shader translation</param> /// <param name="stage">Shader stage</param> /// <param name="gpuVa">GPU virtual address of the shader code</param> /// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param> /// <returns>Compiled graphics shader code</returns> private ShaderCodeHolder TranslateGraphicsShader(GpuState state, TranslationFlags flags, ShaderStage stage, ulong gpuVa, ulong gpuVaA = 0) { if (gpuVa == 0) { return(null); } GpuAccessor gpuAccessor = new GpuAccessor(_context, state, (int)stage - 1); if (gpuVaA != 0) { ShaderProgram program = Translator.Translate(gpuVaA, gpuVa, gpuAccessor, flags); byte[] codeA = _context.MemoryManager.GetSpan(gpuVaA, program.SizeA).ToArray(); byte[] codeB = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray(); _dumper.Dump(codeA, compute: false, out string fullPathA, out string codePathA); _dumper.Dump(codeB, compute: false, out string fullPathB, out string codePathB); if (fullPathA != null && fullPathB != null && codePathA != null && codePathB != null) { program.Prepend("// " + codePathB); program.Prepend("// " + fullPathB); program.Prepend("// " + codePathA); program.Prepend("// " + fullPathA); } return(new ShaderCodeHolder(program, codeB, codeA)); } else { ShaderProgram program = Translator.Translate(gpuVa, gpuAccessor, flags); byte[] code = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray(); _dumper.Dump(code, compute: false, out string fullPath, out string codePath); if (fullPath != null && codePath != null) { program.Prepend("// " + codePath); program.Prepend("// " + fullPath); } return(new ShaderCodeHolder(program, code)); } }
/// <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(resourceId); int uniformBlockCount; GL.GetProgram(resourceId, PdxActiveUniformBlocks, out uniformBlockCount); for (int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { // TODO: get previous name to find te actual constant buffer in the reflexion #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES const int sbCapacity = 128; int length; var sb = new StringBuilder(sbCapacity); GL.GetActiveUniformBlockName(resourceId, uniformBlockIndex, sbCapacity, out length, sb); var constantBufferName = sb.ToString(); #else var constantBufferName = GL.GetActiveUniformBlockName(resourceId, uniformBlockIndex); #endif var constantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == constantBufferName); if (constantBufferDescriptionIndex == -1) { reflectionResult.Error("Unable to find the constant buffer description [{0}]", constantBufferName); return; } var constantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.RawName == constantBufferName); if (constantBufferIndex == -1) { reflectionResult.Error("Unable to find the constant buffer [{0}]", constantBufferName); return; } var constantBufferDescription = effectReflection.ConstantBuffers[constantBufferDescriptionIndex]; var constantBuffer = effectReflection.ResourceBindings[constantBufferIndex]; GL.GetActiveUniformBlock(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockDataSize, out constantBufferDescription.Size); int uniformCount; GL.GetActiveUniformBlock(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniforms, out uniformCount); // set the binding GL.UniformBlockBinding(resourceId, 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(resourceId, uniformBlockIndex, ActiveUniformBlockParameter.UniformBlockActiveUniformIndices, uniformIndices); GL.GetActiveUniforms(resourceId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformOffset, uniformOffsets); GL.GetActiveUniforms(resourceId, uniformIndices.Length, uniformIndices, ActiveUniformParameter.UniformType, uniformTypes); for (int uniformIndex = 0; uniformIndex < uniformIndices.Length; ++uniformIndex) { #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES int size; ActiveUniformType aut; GL.GetActiveUniform(resourceId, uniformIndices[uniformIndex], sbCapacity, out length, out size, out aut, sb); uniformNames[uniformIndex] = sb.ToString(); #else uniformNames[uniformIndex] = GL.GetActiveUniformName(resourceId, 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].Param.RawName == variableIndexGroup.Name) { variableIndex = tentativeIndex; break; } } if (variableIndex == -1) { reflectionResult.Error("Unable to find uniform [{0}] in constant buffer [{1}]", variableIndexGroup.Name, constantBufferName); continue; } var variable = constantBufferDescription.Members[variableIndex]; variable.Param.Type = GetTypeFromActiveUniformType(variableIndexGroup.Type); variable.Offset = variableIndexGroup.Offset; variable.Size = variableIndexGroup.NextOffset - variableIndexGroup.Offset; constantBufferDescription.Members[variableIndex] = variable; } constantBufferDescription.Stage = stage; constantBufferDescription.Type = ConstantBufferType.ConstantBuffer; constantBuffer.SlotCount = 1; // constant buffers are not arrays constantBuffer.SlotStart = uniformBlockIndex; constantBuffer.Stage = stage; // store the new values effectReflection.ConstantBuffers[constantBufferDescriptionIndex] = constantBufferDescription; effectReflection.ResourceBindings[constantBufferIndex] = constantBuffer; } //#endif // 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 EffectParameterResourceData { Param = { RawName = "NoSampler", KeyName = "NoSampler", Class = EffectParameterClass.Sampler }, SlotStart = -1 }; effectBytecode.Reflection.ResourceBindings.Add(noSampler); bool usingSamplerNoSampler = false; int activeUniformCount; GL.GetProgram(resourceId, ProgramParameter.ActiveUniforms, out activeUniformCount); #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES var uniformTypes = new int[activeUniformCount]; GL.GetActiveUniforms(resourceId, activeUniformCount, Enumerable.Range(0, activeUniformCount).ToArray(), ActiveUniformParameter.UniformType, uniformTypes); #endif #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES if (GraphicsDevice.IsOpenGLES2) { // Register global "fake" cbuffer //var constantBuffer = new ShaderReflectionConstantBuffer // { // Name = "$Globals", // Variables = new List<ShaderReflectionVariable>(), // Type = ConstantBufferType.ConstantBuffer // }; //shaderReflection.ConstantBuffers.Add(constantBuffer); //shaderReflection.BoundResources.Add(new InputBindingDescription { BindPoint = 0, BindCount = 1, Name = constantBuffer.Name, Type = ShaderInputType.ConstantBuffer }); // reset the size of the constant buffers foreach (var constantBuffer in effectReflection.ConstantBuffers) constantBuffer.Size = 0; // set the state of the constant buffers foreach (var constantBuffer in effectReflection.ConstantBuffers) constantBuffer.Stage = stage; for (int i = 0; i < effectReflection.ResourceBindings.Count; i++) { if (effectReflection.ResourceBindings[i].Param.Class != EffectParameterClass.ConstantBuffer) continue; var globalConstantBufferCopy = effectReflection.ResourceBindings[i]; globalConstantBufferCopy.Stage = stage; effectReflection.ResourceBindings[i] = globalConstantBufferCopy; } //Create a Globals constant buffer if necessary var globalConstantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == "Globals"); var globalConstantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.RawName == "Globals"); if (globalConstantBufferDescriptionIndex == -1 && globalConstantBufferIndex == -1) { var newConstantBufferDescription = new ShaderConstantBufferDescription { Name = "Globals", Stage = stage, Type = ConstantBufferType.ConstantBuffer, Size = 0, Members = new EffectParameterValueData[0], }; var newConstantBuffer = new EffectParameterResourceData { Stage = stage, SlotStart = 0, SlotCount = 1, Param = { RawName = "Globals", KeyName = "Globals", Type = EffectParameterType.ConstantBuffer, Class = EffectParameterClass.ConstantBuffer } }; effectReflection.ConstantBuffers.Add(newConstantBufferDescription); effectReflection.ResourceBindings.Add(newConstantBuffer); globalConstantBufferDescriptionIndex = effectReflection.ConstantBuffers.Count - 1; globalConstantBufferIndex = effectReflection.ResourceBindings.Count - 1; } // Merge all the variables in the Globals constant buffer if (globalConstantBufferDescriptionIndex != -1 && globalConstantBufferIndex != -1) { var globalConstantBufferDescription = effectReflection.ConstantBuffers[globalConstantBufferDescriptionIndex]; for (int cstDescrIndex = 0; cstDescrIndex < effectReflection.ConstantBuffers.Count; ++cstDescrIndex) { if (cstDescrIndex == globalConstantBufferDescriptionIndex) continue; var currentConstantBufferDescription = effectReflection.ConstantBuffers[cstDescrIndex]; globalConstantBufferDescription.Members = ArrayExtensions.Concat( globalConstantBufferDescription.Members, currentConstantBufferDescription.Members); effectReflection.ResourceBindings.RemoveAll(x => x.Param.RawName == currentConstantBufferDescription.Name); } // only keep the active uniforms globalConstantBufferDescription.Members = globalConstantBufferDescription.Members.Where(x => GL.GetUniformLocation(resourceId, #if SILICONSTUDIO_PLATFORM_ANDROID new StringBuilder(x.Param.RawName) #else x.Param.RawName #endif ) >= 0).ToArray(); // remove all the constant buffers and their resource bindings except the Globals one effectReflection.ConstantBuffers.Clear(); effectReflection.ConstantBuffers.Add(globalConstantBufferDescription); } else if (globalConstantBufferDescriptionIndex != -1 && globalConstantBufferIndex == -1) { reflectionResult.Error("Globals constant buffer has a description and no resource binding"); } else if (globalConstantBufferDescriptionIndex == -1 && globalConstantBufferIndex != -1) { reflectionResult.Error("Globals constant buffer has a description and no resource binding"); } } #endif int textureUnitCount = 0; for (int activeUniformIndex = 0; activeUniformIndex < activeUniformCount; ++activeUniformIndex) { #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES var uniformType = (ActiveUniformType)uniformTypes[activeUniformIndex]; var uniformName = GL.GetActiveUniformName(resourceId, activeUniformIndex); #else ActiveUniformType uniformType; int uniformCount; var uniformName = GL.GetActiveUniform(resourceId, activeUniformIndex, out uniformCount, out uniformType); //int uniformSize; //GL.GetActiveUniform(resourceId, activeUniformIndex, out uniformSize, ActiveUniformType.Float); #endif switch (uniformType) { #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES case ActiveUniformType.Bool: case ActiveUniformType.Int: AddUniform(effectReflection, sizeof(int) * 1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec2: case ActiveUniformType.IntVec2: AddUniform(effectReflection, sizeof(int) * 2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec3: case ActiveUniformType.IntVec3: AddUniform(effectReflection, sizeof(int) * 3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.BoolVec4: case ActiveUniformType.IntVec4: AddUniform(effectReflection, sizeof(int) * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.Float: AddUniform(effectReflection, sizeof(float) * 1, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec2: AddUniform(effectReflection, sizeof(float) * 2, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec3: AddUniform(effectReflection, sizeof(float) * 3, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatVec4: AddUniform(effectReflection, sizeof(float) * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat4: AddUniform(effectReflection, sizeof(float) * 4 * 4, uniformCount, uniformName, uniformType); break; case ActiveUniformType.FloatMat2: case ActiveUniformType.FloatMat3: throw new NotImplementedException(); #endif #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES case ActiveUniformType.Sampler1D: #endif case ActiveUniformType.Sampler2D: case ActiveUniformType.Sampler3D: // TODO: remove Texture3D that is not available in OpenGL ES 2 case ActiveUniformType.SamplerCube: #if SILICONSTUDIO_PLATFORM_ANDROID var uniformIndex = GL.GetUniformLocation(resourceId, new StringBuilder(uniformName)); #else var uniformIndex = GL.GetUniformLocation(resourceId, uniformName); #endif // 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.Param.RawName == textureName); samplerReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.Param.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 [{0}]", 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.Param.Type = GetTypeFromActiveUniformType(uniformType); textureReflection.SlotStart = textureUnitCount; textureReflection.SlotCount = 1; // TODO: texture arrays textureReflection.Param.Class = EffectParameterClass.ShaderResourceView; samplerReflection.Stage = stage; samplerReflection.SlotStart = textureUnitCount; samplerReflection.SlotCount = 1; // TODO: texture arrays samplerReflection.Param.Class = EffectParameterClass.Sampler; 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); } GL.UseProgram(currentProgram); }
/// <summary> /// Sets an unordered access view to the shader pipeline. /// </summary> /// <param name="stage">The stage.</param> /// <param name="slot">The slot.</param> /// <param name="unorderedAccessView">The unordered access view.</param> /// <exception cref="System.ArgumentException">Invalid stage.;stage</exception> public void SetUnorderedAccessView(ShaderStage stage, int slot, GraphicsResource unorderedAccessView) { throw new NotImplementedException(); }
public bool IsSharedPixelShaderUsingMethods(ShaderStage entryPoint) { return(entryPoint == ShaderStage.Shadow_Generate); }
public void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer) { SetBuffer(index, stage, buffer, isStorage: false); }
public bool IsSharedPixelShaderWithoutMethod(ShaderStage entryPoint) { return(false); }
public static Shader New(GraphicsDevice device, ShaderStage shaderStage, byte[] shaderBytecode) { return new Shader(device, shaderStage, shaderBytecode); }
public bool IsVertexShaderShared(ShaderStage entryPoint) { return(true); }