public PhysicsDebugEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, bytecode ?? (bytecode = BinarySerialization.Read <EffectBytecode>(binaryBytecode))) { Color = new Color4(1.0f); WorldViewProj = Matrix.Identity; UseUv = true; }
private EffectProgram(GraphicsDevice device, EffectBytecode bytecode) : base(device) { effectBytecode = bytecode; Reflection = effectBytecode.Reflection; CreateShaders(); }
private EffectBytecode LoadEffectBytecode(DatabaseFileProvider database, ObjectId bytecodeId) { EffectBytecode bytecode = null; if (!bytecodes.TryGetValue(bytecodeId, out bytecode)) { if (!bytecodesByPassingStorage.Contains(bytecodeId) && database.ObjectDatabase.Exists(bytecodeId)) { using (var stream = database.ObjectDatabase.OpenStream(bytecodeId)) { bytecode = EffectBytecode.FromStream(stream); } } if (bytecode != null) { bytecodes.Add(bytecodeId, bytecode); } } // Always check that the bytecode is in sync with hash sources on all platforms if (bytecode != null && IsBytecodeObsolete(bytecode)) { bytecodes.Remove(bytecodeId); bytecode = null; } return(bytecode); }
// Note: no need to store RTV/DSV formats internal PipelineState(GraphicsDevice graphicsDevice, PipelineStateDescription pipelineStateDescription) : base(graphicsDevice) { // First time, build caches var pipelineStateCache = GetPipelineStateCache(); // Effect this.rootSignature = pipelineStateDescription.RootSignature; this.effectBytecode = pipelineStateDescription.EffectBytecode; CreateShaders(pipelineStateCache); if (rootSignature != null && effectBytecode != null) { ResourceBinder.Compile(graphicsDevice, rootSignature.EffectDescriptorSetReflection, this.effectBytecode); } // TODO: Cache over Effect|RootSignature to create binding operations // States blendState = pipelineStateCache.BlendStateCache.Instantiate(pipelineStateDescription.BlendState); this.sampleMask = pipelineStateDescription.SampleMask; rasterizerState = pipelineStateCache.RasterizerStateCache.Instantiate(pipelineStateDescription.RasterizerState); depthStencilState = pipelineStateCache.DepthStencilStateCache.Instantiate(pipelineStateDescription.DepthStencilState); CreateInputLayout(pipelineStateDescription.InputElements); primitiveTopology = (SharpDX.Direct3D.PrimitiveTopology)pipelineStateDescription.PrimitiveType; }
private Effect CreateEffect(string effectName, EffectBytecode bytecode, ShaderMixinParameters usedParameters) { Effect effect; lock (cachedEffects) { if (!cachedEffects.TryGetValue(bytecode, out effect)) { effect = new Effect(graphicsDeviceService.GraphicsDevice, bytecode, usedParameters) { Name = effectName }; cachedEffects.Add(bytecode, effect); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP foreach (var type in bytecode.HashSources.Keys) { // TODO: the "/path" is hardcoded, used in ImportStreamCommand and ShaderSourceManager. Find a place to share this correctly. using (var pathStream = Asset.OpenAsStream(EffectCompilerBase.GetStoragePathFromShaderType(type) + "/path")) using (var reader = new StreamReader(pathStream)) { var path = reader.ReadToEnd(); directoryWatcher.Track(path); } } #endif } } return(effect); }
private Effect CreateEffect(EffectBytecode bytecode, ShaderMixinParameters usedParameters) { Effect effect; lock (cachedEffects) { if (!cachedEffects.TryGetValue(bytecode, out effect)) { effect = new Effect(graphicsDeviceService.GraphicsDevice, bytecode, usedParameters); effect.Name = bytecode.Name; cachedEffects.Add(bytecode, effect); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP foreach (var sourcePath in bytecode.HashSources.Keys) { using (var pathStream = Asset.OpenAsStream(sourcePath + "/path")) using (var reader = new StreamReader(pathStream)) { var path = reader.ReadToEnd(); directoryWatcher.Track(path); } } #endif } } return(effect); }
protected override void DrawCore(RenderDrawContext context) { if (EffectInstance.UpdateEffect(GraphicsDevice) || pipelineStateDirty || previousBytecode != EffectInstance.Effect.Bytecode) { // The EffectInstance might have been updated from outside previousBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.SetDefaults(); pipelineState.State.RootSignature = EffectInstance.RootSignature; pipelineState.State.EffectBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.InputElements = PrimitiveQuad.VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = PrimitiveQuad.PrimitiveType; pipelineState.State.BlendState = blendState; pipelineState.State.Output.CaptureState(context.CommandList); pipelineState.Update(); pipelineStateDirty = false; } context.CommandList.SetPipelineState(pipelineState.CurrentState); EffectInstance.Apply(context.GraphicsContext); // Draw a full screen quad context.GraphicsDevice.PrimitiveQuad.Draw(context.CommandList); }
protected override unsafe void DrawCore(RenderDrawContext context) { // Clear render targets if there is a dependency conflict (D3D11 warning) if (delaySetRenderTargets) { context.CommandList.ResetTargets(); } if (EffectInstance.UpdateEffect(GraphicsDevice) || pipelineStateDirty || previousBytecode != EffectInstance.Effect.Bytecode) { // The EffectInstance might have been updated from outside previousBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.RootSignature = EffectInstance.RootSignature; pipelineState.State.EffectBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.BlendState = blendState; pipelineState.State.DepthStencilState = depthStencilState; var renderTargetCount = OutputCount; if (renderTargetCount > 0) { // Special case: texture cube var isTextureCube = GetOutput(0).ViewDimension == TextureDimension.TextureCube; if (isTextureCube) { renderTargetCount = 6; } // Capture output state manually (since render targets might not be bound if delaySetRenderTargets is set to true) pipelineState.State.Output.RenderTargetCount = renderTargetCount; fixed(PixelFormat *pixelFormatStart = &pipelineState.State.Output.RenderTargetFormat0) for (int i = 0; i < renderTargetCount; ++i) { pixelFormatStart[i] = GetOutput(isTextureCube ? 0 : i).ViewFormat; } } if (HasDepthStencilOutput) { pipelineState.State.Output.DepthStencilFormat = DepthStencil.Format; } pipelineState.Update(); pipelineStateDirty = false; } context.CommandList.SetPipelineState(pipelineState.CurrentState); EffectInstance.Apply(context.GraphicsContext); // Now that resources are bound, set render targets if (delaySetRenderTargets) { SetRenderTargets(context); } // Draw a full screen quad context.GraphicsDevice.PrimitiveQuad.Draw(context.CommandList); }
public PhysicsDebugEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, bytecode ?? (bytecode = EffectBytecode.FromBytesSafe(binaryBytecode))) { parameters = new ParameterCollection(); Color = new Color4(1.0f); WorldViewProj = Matrix.Identity; UseUv = true; }
internal EffectProgram(GraphicsDevice device, EffectBytecode bytecode, bool emulateDepthClamp) : base(device) { effectBytecode = bytecode; this.emulateDepthClamp = emulateDepthClamp; // TODO OPENGL currently we modify the reflection info; need to find a better way to deal with that Reflection = effectBytecode.Reflection; CreateShaders(); }
private bool IsBytecodeObsolete(EffectBytecode bytecode) { foreach (var hashSource in bytecode.HashSources) { if (GetShaderSourceHash(hashSource.Key) != hashSource.Value) { return(true); } } return(false); }
private bool IsBytecodeObsolete(EffectBytecode bytecode, HashSet <string> modifiedShaders) { // Don't use linq foreach (KeyValuePair <string, ObjectId> x in bytecode.HashSources) { if (modifiedShaders.Contains(x.Key)) { return(true); } } return(false); }
public EffectProgram GetOrCreateShader(GraphicsDevice graphicsDevice, EffectBytecode bytecode) { lock (ShaderLibrary) { EffectProgram effectProgram; if (!ShaderLibrary.TryGetValue(bytecode, out effectProgram)) { effectProgram = new EffectProgram(graphicsDevice, bytecode); ShaderLibrary.Add(bytecode, effectProgram); } return(effectProgram); } }
/// <summary> /// Checks if the specified bytecode is synchronized with latest source /// </summary> /// <param name="byteCode">The byte code.</param> /// <param name="database">The database.</param> /// <returns><c>true</c> if bytecode is synchronized with latest source, <c>false</c> otherwise.</returns> private static bool CheckBytecodeInSyncAgainstSources(EffectBytecode byteCode, DatabaseFileProvider database) { var usedSources = byteCode.HashSources; // Find a bytecode that is using the same hash for its pdxsl sources foreach (var usedSource in usedSources) { ObjectId currentId; if (!database.AssetIndexMap.TryGetValue(usedSource.Key, out currentId) || usedSource.Value != currentId) { return(false); } } return(true); }
internal void InitializeFrom(GraphicsDevice device, EffectBytecode bytecode) { if (device == null) { throw new ArgumentNullException("device"); } if (bytecode == null) { throw new ArgumentNullException("bytecode"); } this.graphicsDeviceDefault = device; this.bytecode = bytecode; Initialize(); }
/// <summary> /// Initializes a new instance of the <see cref="Effect"/> class. /// </summary> /// <param name="device">The device.</param> /// <param name="bytecode">The bytecode.</param> /// <param name="usedParameters">The parameters used to create this shader (from a pdxfx).</param> /// <exception cref="System.ArgumentNullException"> /// device /// or /// bytecode /// </exception> public Effect(GraphicsDevice device, EffectBytecode bytecode, ParameterCollection usedParameters = null) { if (device == null) { throw new ArgumentNullException("device"); } if (bytecode == null) { throw new ArgumentNullException("bytecode"); } this.graphicsDeviceDefault = device; this.bytecode = bytecode; Initialize(usedParameters); }
/// <summary> /// Initializes a new instance of the <see cref="Effect"/> class. /// </summary> /// <param name="device">The device.</param> /// <param name="bytecode">The bytecode.</param> /// <param name="usedParameters">The parameters used to create this shader (from a pdxfx).</param> /// <exception cref="System.ArgumentNullException"> /// device /// or /// bytecode /// </exception> public Effect(GraphicsDevice device, EffectBytecode bytecode, ParameterCollection usedParameters = null) { if (device == null) { throw new ArgumentNullException("device"); } if (bytecode == null) { throw new ArgumentNullException("bytecode"); } parameters = new ParameterCollection(); Initialize(device, bytecode, usedParameters); Changed = false; }
protected BatchBase(GraphicsDevice device, EffectBytecode defaultEffectByteCode, EffectBytecode defaultEffectByteCodeSRgb, ResourceBufferInfo resourceBufferInfo, VertexDeclaration vertexDeclaration, int indexSize = sizeof(short)) { if (defaultEffectByteCode == null) { throw new ArgumentNullException(nameof(defaultEffectByteCode)); } if (defaultEffectByteCodeSRgb == null) { throw new ArgumentNullException(nameof(defaultEffectByteCodeSRgb)); } if (resourceBufferInfo == null) { throw new ArgumentNullException("resourceBufferInfo"); } if (vertexDeclaration == null) { throw new ArgumentNullException("vertexDeclaration"); } GraphicsDevice = device; DefaultEffect = new Effect(device, defaultEffectByteCode) { Name = "BatchDefaultEffect" }; DefaultEffectSRgb = new Effect(device, defaultEffectByteCodeSRgb) { Name = "BatchDefaultEffectSRgb" }; drawsQueue = new ElementInfo[resourceBufferInfo.BatchCapacity]; drawTextures = new Texture[resourceBufferInfo.BatchCapacity]; TextureComparer = new TextureIdComparer(); BackToFrontComparer = new SpriteBackToFrontComparer(); FrontToBackComparer = new SpriteFrontToBackComparer(); // set the vertex layout and size indexStructSize = indexSize; vertexStructSize = vertexDeclaration.CalculateSize(); parameters = new ParameterCollection(); defaultParameterCollectionGroup = new EffectParameterCollectionGroup(device, DefaultEffect, new[] { parameters }); // Creates the vertex buffer (shared by within a device context). ResourceContext = GraphicsDevice.GetOrCreateSharedData(GraphicsDeviceSharedDataType.PerContext, resourceBufferInfo.ResourceKey, d => new DeviceResourceContext(GraphicsDevice, DefaultEffect, vertexDeclaration, resourceBufferInfo, indexStructSize)); }
protected BatchBase(GraphicsDevice device, EffectBytecode defaultEffectByteCode, EffectBytecode defaultEffectByteCodeSRgb, ResourceBufferInfo resourceBufferInfo, VertexDeclaration vertexDeclaration, int indexSize = sizeof(short)) { if (defaultEffectByteCode == null) { throw new ArgumentNullException(nameof(defaultEffectByteCode)); } if (defaultEffectByteCodeSRgb == null) { throw new ArgumentNullException(nameof(defaultEffectByteCodeSRgb)); } if (resourceBufferInfo == null) { throw new ArgumentNullException("resourceBufferInfo"); } if (vertexDeclaration == null) { throw new ArgumentNullException("vertexDeclaration"); } graphicsDevice = device; mutablePipeline = new MutablePipelineState(device); // TODO GRAPHICS REFACTOR Should we initialize FX lazily? DefaultEffect = new EffectInstance(new Effect(device, defaultEffectByteCode) { Name = "BatchDefaultEffect" }); DefaultEffectSRgb = new EffectInstance(new Effect(device, defaultEffectByteCodeSRgb) { Name = "BatchDefaultEffectSRgb" }); drawsQueue = new ElementInfo[resourceBufferInfo.BatchCapacity]; drawTextures = new Texture[resourceBufferInfo.BatchCapacity]; TextureComparer = new TextureIdComparer(); BackToFrontComparer = new SpriteBackToFrontComparer(); FrontToBackComparer = new SpriteFrontToBackComparer(); // set the vertex layout and size indexStructSize = indexSize; vertexStructSize = vertexDeclaration.CalculateSize(); // Creates the vertex buffer (shared by within a device context). ResourceContext = graphicsDevice.GetOrCreateSharedData(GraphicsDeviceSharedDataType.PerContext, resourceBufferInfo.ResourceKey, d => new DeviceResourceContext(graphicsDevice, vertexDeclaration, resourceBufferInfo)); }
private EffectProgram(GraphicsDevice device, EffectBytecode bytecode) : base(device) { effectBytecode = bytecode; // make a copy of the effect's reflection before modifying it. Reflection = new EffectReflection { // The members that are not modified and can be shallowly copied. SamplerStates = effectBytecode.Reflection.SamplerStates, ShaderStreamOutputDeclarations = effectBytecode.Reflection.ShaderStreamOutputDeclarations, StreamOutputRasterizedStream = effectBytecode.Reflection.StreamOutputRasterizedStream, StreamOutputStrides = effectBytecode.Reflection.StreamOutputStrides, // The members that are modified and should be deeply copied. ConstantBuffers = effectBytecode.Reflection.ConstantBuffers.Select(cb => cb.Clone()).ToList(), ResourceBindings = new List <EffectParameterResourceData>(effectBytecode.Reflection.ResourceBindings), }; CreateShaders(); }
private KeyValuePair <EffectBytecode, EffectBytecodeCacheLoadSource> LoadEffectBytecode(DatabaseFileProvider database, ObjectId bytecodeId) { KeyValuePair <EffectBytecode, EffectBytecodeCacheLoadSource> bytecodePair; if (!bytecodes.TryGetValue(bytecodeId, out bytecodePair)) { if (!bytecodesByPassingStorage.Contains(bytecodeId) && database.ObjectDatabase.Exists(bytecodeId)) { using (var stream = database.ObjectDatabase.OpenStream(bytecodeId)) { var bytecode = EffectBytecode.FromStream(stream); // Try to read an integer that would specify what kind of cache it belongs to (if undefined because of old versions, mark it as dynamic cache) var cacheSource = EffectBytecodeCacheLoadSource.DynamicCache; if (stream.Position < stream.Length) { var binaryReader = new BinarySerializationReader(stream); cacheSource = (EffectBytecodeCacheLoadSource)binaryReader.ReadInt32(); } bytecodePair = new KeyValuePair <EffectBytecode, EffectBytecodeCacheLoadSource>(bytecode, cacheSource); } } if (bytecodePair.Key != null) { bytecodes.Add(bytecodeId, bytecodePair); } } // Always check that the bytecode is in sync with hash sources on all platforms if (bytecodePair.Key != null && IsBytecodeObsolete(bytecodePair.Key)) { bytecodes.Remove(bytecodeId); bytecodePair = new KeyValuePair <EffectBytecode, EffectBytecodeCacheLoadSource>(null, EffectBytecodeCacheLoadSource.JustCompiled); } return(bytecodePair); }
internal void Initialize(GraphicsDevice device, EffectBytecode byteCode, ParameterCollection usedParameters) { Name = byteCode.Name; graphicsDeviceDefault = device.RootDevice; program = EffectProgram.New(graphicsDeviceDefault, byteCode); reflection = byteCode.Reflection; // prepare resource bindings used internally resourceBindings = new EffectParameterResourceBinding[byteCode.Reflection.ResourceBindings.Count]; for (int i = 0; i < resourceBindings.Length; i++) { resourceBindings[i].Description = byteCode.Reflection.ResourceBindings[i]; } defaultParameters = new ParameterCollection(); inputSignature = program.InputSignature; LoadDefaultParameters(); CompilationParameters = new ParameterCollection(); DefaultCompilationParameters = new ParameterCollection(); if (usedParameters != null) { foreach (var parameter in usedParameters) { if (parameter.Key != CompilerParameters.DebugKey && parameter.Key != CompilerParameters.GraphicsPlatformKey && parameter.Key != CompilerParameters.GraphicsProfileKey) { CompilationParameters.SetObject(parameter.Key, parameter.Value); } } } foreach (var key in CompilationParameters.Keys) { DefaultCompilationParameters.RegisterParameter(key, false); } Changed = true; }
protected override void DrawCore(RenderDrawContext context) { if (string.IsNullOrEmpty(ShaderSourceName)) { return; } Parameters.Set(ComputeEffectShaderKeys.ThreadNumbers, ThreadNumbers); Parameters.Set(ComputeEffectShaderKeys.ComputeShaderName, ShaderSourceName); Parameters.Set(ComputeShaderBaseKeys.ThreadGroupCountGlobal, ThreadGroupCounts); if (EffectInstance.UpdateEffect(GraphicsDevice) || pipelineStateDirty || previousBytecode != EffectInstance.Effect.Bytecode) { // The EffectInstance might have been updated from outside previousBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.SetDefaults(); pipelineState.State.RootSignature = EffectInstance.RootSignature; pipelineState.State.EffectBytecode = EffectInstance.Effect.Bytecode; pipelineState.Update(); pipelineStateDirty = false; } // Apply pipeline state context.CommandList.SetPipelineState(pipelineState.CurrentState); // Apply the effect EffectInstance.Apply(context.GraphicsContext); // Draw a full screen quad context.CommandList.Dispatch(ThreadGroupCounts.X, ThreadGroupCounts.Y, ThreadGroupCounts.Z); // Un-apply //throw new InvalidOperationException(); //EffectInstance.Effect.UnbindResources(GraphicsDevice); }
public EffectBytecodeCompilerResult(EffectBytecode bytecode) : this() { Bytecode = bytecode; CompilationLog = emptyLoggerResult; }
public static ResourceGroupLayout New <T>(GraphicsDevice graphicsDevice, ResourceGroupDescription resourceGroupDescription, EffectBytecode effectBytecode) where T : ResourceGroupLayout, new() { var result = new T { DescriptorSetLayoutBuilder = resourceGroupDescription.DescriptorSetLayout, DescriptorSetLayout = DescriptorSetLayout.New(graphicsDevice, resourceGroupDescription.DescriptorSetLayout), ConstantBufferReflection = resourceGroupDescription.ConstantBufferReflection, Hash = resourceGroupDescription.Hash, }; if (result.ConstantBufferReflection != null) { result.ConstantBufferSize = result.ConstantBufferReflection.Size; result.ConstantBufferHash = result.ConstantBufferReflection.Hash; } return(result); }
public void Compile(GraphicsDevice graphicsDevice, EffectDescriptorSetReflection descriptorSetLayouts, EffectBytecode effectBytecode) { descriptorSetBindings = new BindingOperation[descriptorSetLayouts.Layouts.Count][]; for (int setIndex = 0; setIndex < descriptorSetLayouts.Layouts.Count; setIndex++) { var layout = descriptorSetLayouts.Layouts[setIndex].Layout; if (layout == null) { continue; } var bindingOperations = new List <BindingOperation>(); for (int resourceIndex = 0; resourceIndex < layout.Entries.Count; resourceIndex++) { var layoutEntry = layout.Entries[resourceIndex]; // Find it in shader reflection foreach (var resourceBinding in effectBytecode.Reflection.ResourceBindings) { if (resourceBinding.Stage == ShaderStage.None) { continue; } if (resourceBinding.KeyInfo.Key == layoutEntry.Key) { bindingOperations.Add(new BindingOperation { EntryIndex = resourceIndex, Class = resourceBinding.Class, Stage = resourceBinding.Stage, SlotStart = resourceBinding.SlotStart, ImmutableSampler = layoutEntry.ImmutableSampler, }); } } } descriptorSetBindings[setIndex] = bindingOperations.Count > 0 ? bindingOperations.ToArray() : null; } }
/// <summary> /// Initializes a new instance of the <see cref="Effect"/> class. /// </summary> /// <param name="device">The device.</param> /// <param name="bytecode">The bytecode.</param> /// <param name="usedParameters">The parameters used to create this shader (from a sdfx).</param> /// <exception cref="System.ArgumentNullException"> /// device /// or /// bytecode /// </exception> public Effect(GraphicsDevice device, EffectBytecode bytecode) { InitializeFrom(device, bytecode); }
public EffectBytecodeCompilerResult(EffectBytecode bytecode, EffectBytecodeCacheLoadSource loadSource) : this() { Bytecode = bytecode; CompilationLog = emptyLoggerResult; LoadSource = loadSource; }
public override TaskOrResult <EffectBytecodeCompilerResult> Compile(ShaderMixinSource mixinTree, EffectCompilerParameters effectParameters, CompilerParameters compilerParameters) { var log = new LoggerResult(); // Load D3D compiler dll // Note: No lock, it's probably fine if it gets called from multiple threads at the same time. if (Platform.IsWindowsDesktop && !d3dCompilerLoaded) { NativeLibrary.PreloadLibrary("d3dcompiler_47.dll"); d3dCompilerLoaded = true; } var shaderMixinSource = mixinTree; var fullEffectName = mixinTree.Name; // Make a copy of shaderMixinSource. Use deep clone since shaderMixinSource can be altered during compilation (e.g. macros) var shaderMixinSourceCopy = new ShaderMixinSource(); shaderMixinSourceCopy.DeepCloneFrom(shaderMixinSource); shaderMixinSource = shaderMixinSourceCopy; // Generate platform-specific macros switch (effectParameters.Platform) { case GraphicsPlatform.Direct3D11: shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D11", 1); break; case GraphicsPlatform.Direct3D12: shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_DIRECT3D12", 1); break; case GraphicsPlatform.OpenGL: shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGL", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLCORE", 1); break; case GraphicsPlatform.OpenGLES: shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGL", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES", 1); break; case GraphicsPlatform.Vulkan: shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_API_VULKAN", 1); break; default: throw new NotSupportedException(); } // Generate profile-specific macros shaderMixinSource.AddMacro("SILICONSTUDIO_XENKO_GRAPHICS_PROFILE", (int)effectParameters.Profile); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_1", (int)GraphicsProfile.Level_9_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_2", (int)GraphicsProfile.Level_9_2); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_3", (int)GraphicsProfile.Level_9_3); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_10_0", (int)GraphicsProfile.Level_10_0); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_10_1", (int)GraphicsProfile.Level_10_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_0", (int)GraphicsProfile.Level_11_0); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_1", (int)GraphicsProfile.Level_11_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_2", (int)GraphicsProfile.Level_11_2); // In .xksl, class has been renamed to shader to avoid ambiguities with HLSL shaderMixinSource.AddMacro("class", "shader"); var parsingResult = GetMixinParser().Parse(shaderMixinSource, shaderMixinSource.Macros.ToArray()); // Copy log from parser results to output CopyLogs(parsingResult, log); // Return directly if there are any errors if (parsingResult.HasErrors) { return(new EffectBytecodeCompilerResult(null, log)); } // Convert the AST to HLSL var writer = new SiliconStudio.Shaders.Writer.Hlsl.HlslWriter { EnablePreprocessorLine = false // Allow to output links to original pdxsl via #line pragmas }; writer.Visit(parsingResult.Shader); var shaderSourceText = writer.Text; if (string.IsNullOrEmpty(shaderSourceText)) { log.Error($"No code generated for effect [{fullEffectName}]"); return(new EffectBytecodeCompilerResult(null, log)); } // ------------------------------------------------------- // Save shader log // TODO: TEMP code to allow debugging generated shaders on Windows Desktop #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP var shaderId = ObjectId.FromBytes(Encoding.UTF8.GetBytes(shaderSourceText)); var logDir = Path.Combine(Directory.GetCurrentDirectory(), "log"); if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } var shaderSourceFilename = Path.Combine(logDir, "shader_" + fullEffectName.Replace('.', '_') + "_" + shaderId + ".hlsl"); lock (WriterLock) // protect write in case the same shader is created twice { // Write shader before generating to make sure that we are having a trace before compiling it (compiler may crash...etc.) if (!File.Exists(shaderSourceFilename)) { File.WriteAllText(shaderSourceFilename, shaderSourceText); } } #else string shaderSourceFilename = null; #endif // ------------------------------------------------------- var bytecode = new EffectBytecode { Reflection = parsingResult.Reflection, HashSources = parsingResult.HashSources }; // Select the correct backend compiler IShaderCompiler compiler; switch (effectParameters.Platform) { #if SILICONSTUDIO_PLATFORM_WINDOWS case GraphicsPlatform.Direct3D11: case GraphicsPlatform.Direct3D12: compiler = new Direct3D.ShaderCompiler(); break; #endif case GraphicsPlatform.OpenGL: case GraphicsPlatform.OpenGLES: case GraphicsPlatform.Vulkan: // get the number of render target outputs var rtOutputs = 0; var psOutput = parsingResult.Shader.Declarations.OfType <StructType>().FirstOrDefault(x => x.Name.Text == "PS_OUTPUT"); if (psOutput != null) { foreach (var rto in psOutput.Fields) { var sem = rto.Qualifiers.OfType <Semantic>().FirstOrDefault(); if (sem != null) { // special case SV_Target if (rtOutputs == 0 && sem.Name.Text == "SV_Target") { rtOutputs = 1; break; } for (var i = rtOutputs; i < 8; ++i) { if (sem.Name.Text == ("SV_Target" + i)) { rtOutputs = i + 1; break; } } } } } compiler = new OpenGL.ShaderCompiler(rtOutputs); break; default: throw new NotSupportedException(); } var shaderStageBytecodes = new List <ShaderBytecode>(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP var stageStringBuilder = new StringBuilder(); #endif // if the shader (non-compute) does not have a pixel shader, we should add it for OpenGL and OpenGL ES. if ((effectParameters.Platform == GraphicsPlatform.OpenGL || effectParameters.Platform == GraphicsPlatform.OpenGLES) && !parsingResult.EntryPoints.ContainsKey(ShaderStage.Pixel) && !parsingResult.EntryPoints.ContainsKey(ShaderStage.Compute)) { parsingResult.EntryPoints.Add(ShaderStage.Pixel, null); } foreach (var stageBinding in parsingResult.EntryPoints) { // Compile // TODO: We could compile stages in different threads to improve compiler throughput? var result = compiler.Compile(shaderSourceText, stageBinding.Value, stageBinding.Key, effectParameters, bytecode.Reflection, shaderSourceFilename); result.CopyTo(log); if (result.HasErrors) { continue; } // ------------------------------------------------------- // Append bytecode id to shader log #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP stageStringBuilder.AppendLine("@G {0} => {1}".ToFormat(stageBinding.Key, result.Bytecode.Id)); if (result.DisassembleText != null) { stageStringBuilder.Append(result.DisassembleText); } #endif // ------------------------------------------------------- shaderStageBytecodes.Add(result.Bytecode); // When this is a compute shader, there is no need to scan other stages if (stageBinding.Key == ShaderStage.Compute) { break; } } // Remove unused reflection data, as it is entirely resolved at compile time. CleanupReflection(bytecode.Reflection); bytecode.Stages = shaderStageBytecodes.ToArray(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP lock (WriterLock) // protect write in case the same shader is created twice { var builder = new StringBuilder(); builder.AppendLine("/**************************"); builder.AppendLine("***** Compiler Parameters *****"); builder.AppendLine("***************************"); builder.Append("@P EffectName: "); builder.AppendLine(fullEffectName ?? ""); builder.Append(compilerParameters?.ToStringPermutationsDetailed()); builder.AppendLine("***************************"); if (bytecode.Reflection.ConstantBuffers.Count > 0) { builder.AppendLine("**** ConstantBuffers ****"); builder.AppendLine("***************************"); foreach (var cBuffer in bytecode.Reflection.ConstantBuffers) { builder.AppendFormat("cbuffer {0} [Size: {1}]", cBuffer.Name, cBuffer.Size).AppendLine(); foreach (var parameter in cBuffer.Members) { builder.AppendFormat("@C {0} => {1}", parameter.RawName, parameter.KeyInfo.KeyName).AppendLine(); } } builder.AppendLine("***************************"); } if (bytecode.Reflection.ResourceBindings.Count > 0) { builder.AppendLine("****** Resources ******"); builder.AppendLine("***************************"); foreach (var resource in bytecode.Reflection.ResourceBindings) { builder.AppendFormat("@R {0} => {1} [Stage: {2}, Slot: ({3}-{4})]", resource.RawName, resource.KeyInfo.KeyName, resource.Stage, resource.SlotStart, resource.SlotStart + resource.SlotCount - 1).AppendLine(); } builder.AppendLine("***************************"); } if (bytecode.HashSources.Count > 0) { builder.AppendLine("***** Sources *****"); builder.AppendLine("***************************"); foreach (var hashSource in bytecode.HashSources) { builder.AppendFormat("@S {0} => {1}", hashSource.Key, hashSource.Value).AppendLine(); } builder.AppendLine("***************************"); } if (bytecode.Stages.Length > 0) { builder.AppendLine("***** Stages *****"); builder.AppendLine("***************************"); builder.Append(stageStringBuilder); builder.AppendLine("***************************"); } builder.AppendLine("*************************/"); // Re-append the shader with all informations builder.Append(shaderSourceText); File.WriteAllText(shaderSourceFilename, builder.ToString()); } #endif return(new EffectBytecodeCompilerResult(bytecode, log)); }
public override TaskOrResult<EffectBytecodeCompilerResult> Compile(ShaderMixinSource mixinTree, CompilerParameters compilerParameters) { var log = new LoggerResult(); // Load D3D compiler dll // Note: No lock, it's probably fine if it gets called from multiple threads at the same time. if (Platform.IsWindowsDesktop && !d3dCompilerLoaded) { NativeLibrary.PreloadLibrary("d3dcompiler_47.dll"); d3dCompilerLoaded = true; } var shaderMixinSource = mixinTree; var fullEffectName = mixinTree.Name; var usedParameters = mixinTree.UsedParameters; // Make a copy of shaderMixinSource. Use deep clone since shaderMixinSource can be altered during compilation (e.g. macros) var shaderMixinSourceCopy = new ShaderMixinSource(); shaderMixinSourceCopy.DeepCloneFrom(shaderMixinSource); shaderMixinSource = shaderMixinSourceCopy; // Generate platform-specific macros var platform = usedParameters.Get(CompilerParameters.GraphicsPlatformKey); switch (platform) { case GraphicsPlatform.Direct3D11: shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D11", 1); break; case GraphicsPlatform.OpenGL: shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLCORE", 1); break; case GraphicsPlatform.OpenGLES: shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL", 1); shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES", 1); break; default: throw new NotSupportedException(); } // Generate profile-specific macros var profile = usedParameters.Get(CompilerParameters.GraphicsProfileKey); shaderMixinSource.AddMacro("SILICONSTUDIO_PARADOX_GRAPHICS_PROFILE", (int)profile); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_1", (int)GraphicsProfile.Level_9_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_2", (int)GraphicsProfile.Level_9_2); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_9_3", (int)GraphicsProfile.Level_9_3); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_10_0", (int)GraphicsProfile.Level_10_0); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_10_1", (int)GraphicsProfile.Level_10_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_0", (int)GraphicsProfile.Level_11_0); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_1", (int)GraphicsProfile.Level_11_1); shaderMixinSource.AddMacro("GRAPHICS_PROFILE_LEVEL_11_2", (int)GraphicsProfile.Level_11_2); var parsingResult = GetMixinParser().Parse(shaderMixinSource, shaderMixinSource.Macros.ToArray()); // Copy log from parser results to output CopyLogs(parsingResult, log); // Return directly if there are any errors if (parsingResult.HasErrors) { return new EffectBytecodeCompilerResult(null, log); } // Convert the AST to HLSL var writer = new SiliconStudio.Shaders.Writer.Hlsl.HlslWriter { EnablePreprocessorLine = true // Allow to output links to original pdxsl via #line pragmas }; writer.Visit(parsingResult.Shader); var shaderSourceText = writer.Text; if (string.IsNullOrEmpty(shaderSourceText)) { log.Error("No code generated for effect [{0}]", fullEffectName); return new EffectBytecodeCompilerResult(null, log); } // ------------------------------------------------------- // Save shader log // TODO: TEMP code to allow debugging generated shaders on Windows Desktop #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP var shaderId = ObjectId.FromBytes(Encoding.UTF8.GetBytes(shaderSourceText)); var logDir = "log"; if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } var shaderSourceFilename = Path.Combine(logDir, "shader_" + fullEffectName.Replace('.', '_') + "_" + shaderId + ".hlsl"); lock (WriterLock) // protect write in case the same shader is created twice { // Write shader before generating to make sure that we are having a trace before compiling it (compiler may crash...etc.) if (!File.Exists(shaderSourceFilename)) { File.WriteAllText(shaderSourceFilename, shaderSourceText); } } #else string shaderSourceFilename = null; #endif // ------------------------------------------------------- var bytecode = new EffectBytecode { Reflection = parsingResult.Reflection, HashSources = parsingResult.HashSources }; // Select the correct backend compiler IShaderCompiler compiler; switch (platform) { #if SILICONSTUDIO_PLATFORM_WINDOWS case GraphicsPlatform.Direct3D11: compiler = new Direct3D.ShaderCompiler(); break; #endif case GraphicsPlatform.OpenGL: case GraphicsPlatform.OpenGLES: // get the number of render target outputs var rtOutputs = 0; var psOutput = parsingResult.Shader.Declarations.OfType<StructType>().FirstOrDefault(x => x.Name.Text == "PS_OUTPUT"); if (psOutput != null) { foreach (var rto in psOutput.Fields) { var sem = rto.Qualifiers.OfType<Semantic>().FirstOrDefault(); if (sem != null) { // special case SV_Target if (rtOutputs == 0 && sem.Name.Text == "SV_Target") { rtOutputs = 1; break; } for (var i = rtOutputs; i < 8; ++i) { if (sem.Name.Text == ("SV_Target" + i)) { rtOutputs = i + 1; break; } } } } } compiler = new OpenGL.ShaderCompiler(rtOutputs); break; default: throw new NotSupportedException(); } var shaderStageBytecodes = new List<ShaderBytecode>(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP var stageStringBuilder = new StringBuilder(); #endif // if the shader (non-compute) does not have a pixel shader, we should add it on OpenGL ES. if (platform == GraphicsPlatform.OpenGLES && !parsingResult.EntryPoints.ContainsKey(ShaderStage.Pixel) && !parsingResult.EntryPoints.ContainsKey(ShaderStage.Compute)) { parsingResult.EntryPoints.Add(ShaderStage.Pixel, null); } foreach (var stageBinding in parsingResult.EntryPoints) { // Compile // TODO: We could compile stages in different threads to improve compiler throughput? var result = compiler.Compile(shaderSourceText, stageBinding.Value, stageBinding.Key, usedParameters, bytecode.Reflection, shaderSourceFilename); result.CopyTo(log); if (result.HasErrors) { continue; } // ------------------------------------------------------- // Append bytecode id to shader log #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP stageStringBuilder.AppendLine("@G {0} => {1}".ToFormat(stageBinding.Key, result.Bytecode.Id)); #endif // ------------------------------------------------------- shaderStageBytecodes.Add(result.Bytecode); // When this is a compute shader, there is no need to scan other stages if (stageBinding.Key == ShaderStage.Compute) break; } // In case of Direct3D, we can safely remove reflection data as it is entirely resolved at compile time. if (platform == GraphicsPlatform.Direct3D11) { CleanupReflection(bytecode.Reflection); } bytecode.Stages = shaderStageBytecodes.ToArray(); #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP lock (WriterLock) // protect write in case the same shader is created twice { var builder = new StringBuilder(); builder.AppendLine("/**************************"); builder.AppendLine("***** Used Parameters *****"); builder.AppendLine("***************************"); builder.Append("@P EffectName: "); builder.AppendLine(fullEffectName ?? ""); builder.Append(usedParameters.ToStringDetailed()); builder.AppendLine("***************************"); if (bytecode.Reflection.ConstantBuffers.Count > 0) { builder.AppendLine("**** ConstantBuffers ****"); builder.AppendLine("***************************"); foreach (var cBuffer in bytecode.Reflection.ConstantBuffers) { builder.AppendFormat("cbuffer {0} [Stage: {1}, Size: {2}]", cBuffer.Name, cBuffer.Stage, cBuffer.Size).AppendLine(); foreach (var parameter in cBuffer.Members) { builder.AppendFormat("@C {0} => {1}", parameter.Param.RawName, parameter.Param.KeyName).AppendLine(); } } builder.AppendLine("***************************"); } if (bytecode.Reflection.ResourceBindings.Count > 0) { builder.AppendLine("****** Resources ******"); builder.AppendLine("***************************"); foreach (var resource in bytecode.Reflection.ResourceBindings) { var parameter = resource.Param; builder.AppendFormat("@R {0} => {1} [Stage: {2}, Slot: ({3}-{4})]", parameter.RawName, parameter.KeyName, resource.Stage, resource.SlotStart, resource.SlotStart + resource.SlotCount - 1).AppendLine(); } builder.AppendLine("***************************"); } if (bytecode.HashSources.Count > 0) { builder.AppendLine("***** Sources *****"); builder.AppendLine("***************************"); foreach (var hashSource in bytecode.HashSources) { builder.AppendFormat("@S {0} => {1}", hashSource.Key, hashSource.Value).AppendLine(); } builder.AppendLine("***************************"); } if (bytecode.Stages.Length > 0) { builder.AppendLine("***** Stages *****"); builder.AppendLine("***************************"); builder.Append(stageStringBuilder); builder.AppendLine("***************************"); } builder.AppendLine("*************************/"); // Re-append the shader with all informations builder.Append(shaderSourceText); File.WriteAllText(shaderSourceFilename, builder.ToString()); } #endif return new EffectBytecodeCompilerResult(bytecode, log); }
private ViewResourceGroupLayout CreateViewResourceGroupLayout(ResourceGroupDescription resourceGroupDescription, EffectBytecode effectBytecode) { if (resourceGroupDescription.DescriptorSetLayout == null) { return(null); } // We combine both hash for DescriptorSet and cbuffer itself (if it exists) var hash = resourceGroupDescription.Hash; ViewResourceGroupLayout result; if (!viewResourceLayouts.TryGetValue(hash, out result)) { result = new ViewResourceGroupLayout { DescriptorSetLayout = DescriptorSetLayout.New(RenderSystem.GraphicsDevice, resourceGroupDescription.DescriptorSetLayout), ConstantBufferReflection = resourceGroupDescription.ConstantBufferReflection, Entries = new ResourceGroupEntry[RenderSystem.Views.Count], }; for (int index = 0; index < result.Entries.Length; index++) { result.Entries[index].Resources = new ResourceGroup(); } if (resourceGroupDescription.ConstantBufferReflection != null) { result.ConstantBufferSize = resourceGroupDescription.ConstantBufferReflection.Size; result.ConstantBufferHash = resourceGroupDescription.ConstantBufferReflection.Hash; } // Resolve slots result.ConstantBufferOffsets = new int[viewCBufferOffsetSlots.Count]; for (int index = 0; index < viewCBufferOffsetSlots.Count; index++) { ResolveCBufferOffset(result, index, viewCBufferOffsetSlots[index].Variable); } viewResourceLayouts.Add(hash, result); } return(result); }
public EffectBytecodeCompilerResult(EffectBytecode bytecode, LoggerResult compilationLog) { Bytecode = bytecode; CompilationLog = compilationLog; LoadSource = EffectBytecodeCacheLoadSource.JustCompiled; }
public EffectBytecodeCompilerResult(EffectBytecode bytecode, LoggerResult compilationLog) { Bytecode = bytecode; CompilationLog = compilationLog; }
public static ResourceGroupLayout New(GraphicsDevice graphicsDevice, ResourceGroupDescription resourceGroupDescription, EffectBytecode effectBytecode) { return(New <ResourceGroupLayout>(graphicsDevice, resourceGroupDescription, effectBytecode)); }
private bool IsBytecodeObsolete(EffectBytecode bytecode, HashSet<string> modifiedShaders) { // Don't use linq foreach (KeyValuePair<string, ObjectId> x in bytecode.HashSources) { if (modifiedShaders.Contains(x.Key)) return true; } return false; }
public static EffectDescriptorSetReflection New(GraphicsDevice graphicsDevice, EffectBytecode effectBytecode, List <string> effectDescriptorSetSlots, string defaultSetSlot) { // Find resource groups // TODO: We should precompute most of that at compile time in BytecodeReflection // just waiting for format to be more stable var descriptorSetLayouts = new EffectDescriptorSetReflection { DefaultSetSlot = defaultSetSlot }; foreach (var effectDescriptorSetSlot in effectDescriptorSetSlots) { // Find all resources related to this slot name // NOTE: Ordering is mirrored by GLSL layout in Vulkan var descriptorSetLayoutBuilder = new DescriptorSetLayoutBuilder(); bool hasBindings = false; foreach (var resourceBinding in effectBytecode.Reflection.ResourceBindings .Where(x => x.ResourceGroup == effectDescriptorSetSlot || (effectDescriptorSetSlot == defaultSetSlot && (x.ResourceGroup == null || x.ResourceGroup == "Globals"))) .GroupBy(x => new { Key = x.KeyInfo.Key, 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)) // Note: Putting cbuffer first for now { SamplerState samplerState = null; if (resourceBinding.Key.Class == EffectParameterClass.Sampler) { var matchingSamplerState = effectBytecode.Reflection.SamplerStates.FirstOrDefault(x => x.Key == resourceBinding.Key.Key); if (matchingSamplerState != null) { samplerState = SamplerState.New(graphicsDevice, matchingSamplerState.Description); } } hasBindings = true; descriptorSetLayoutBuilder.AddBinding(resourceBinding.Key.Key, resourceBinding.Key.LogicalGroup, resourceBinding.Key.Class, resourceBinding.Key.Type, resourceBinding.Key.ElementType, resourceBinding.Key.SlotCount, samplerState); } descriptorSetLayouts.AddLayout(effectDescriptorSetSlot, hasBindings ? descriptorSetLayoutBuilder : null); } return(descriptorSetLayouts); }
private bool IsBytecodeObsolete(EffectBytecode bytecode) { foreach (var hashSource in bytecode.HashSources) { if (GetShaderSourceHash(hashSource.Key) != hashSource.Value) { return true; } } return false; }