private void EnsureShadersReady() { if (!_initialized) { CheckProgramLink(true); ProgramLinkStatus resultStatus = ProgramLinkStatus.Success; for (int i = 0; i < _shaders.Length; i++) { var shader = _shaders[i]; if (shader.CompileStatus != ProgramLinkStatus.Success) { resultStatus = ProgramLinkStatus.Failure; } _infos[i] = shader.GetInfo(); } // If the link status was already set as failure by background compilation, prefer that decision. if (LinkStatus != ProgramLinkStatus.Failure) { LinkStatus = resultStatus; } _initialized = true; } }
public ProgramLinkStatus CheckProgramLink(bool blocking) { if (LinkStatus == ProgramLinkStatus.Incomplete) { ProgramLinkStatus resultStatus = ProgramLinkStatus.Success; foreach (Shader shader in _shaders) { if (shader.CompileStatus == ProgramLinkStatus.Incomplete) { if (blocking) { // Wait for this shader to finish compiling. shader.WaitForCompile(); if (shader.CompileStatus != ProgramLinkStatus.Success) { resultStatus = ProgramLinkStatus.Failure; } } else { return(ProgramLinkStatus.Incomplete); } } } return(resultStatus); } return(LinkStatus); }
private void EnsureShadersReady() { if (!_initialized) { CheckProgramLink(true); ProgramLinkStatus resultStatus = ProgramLinkStatus.Success; for (int i = 0; i < _shaders.Length; i++) { var shader = (Shader)_shaders[i]; if (shader.CompileStatus != ProgramLinkStatus.Success) { resultStatus = ProgramLinkStatus.Failure; } _infos[i] = shader.GetInfo(); } LinkStatus = resultStatus; _initialized = true; } }
public ProgramLinkStatus CheckProgramLink(bool blocking) { if (!blocking && HwCapabilities.SupportsParallelShaderCompile) { GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed); if (completed == 0) { return(ProgramLinkStatus.Incomplete); } } GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status); DeleteShaders(); if (status == 0) { // Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log. _status = ProgramLinkStatus.Failure; Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed."); } else { _status = ProgramLinkStatus.Success; } return(_status); }
public void ProcessQueue() { for (int i = 0; i < _inProgress.Count; i++) { ThreadedProgram program = _inProgress[i]; ProgramLinkStatus status = program.Base.CheckProgramLink(false); if (status != ProgramLinkStatus.Incomplete) { program.Compiled = true; _inProgress.RemoveAt(i--); } } int freeSpace = MaxConcurrentCompilations - _inProgress.Count; for (int i = 0; i < freeSpace; i++) { // Begin compilation of some programs in the compile queue. IProgramRequest program; lock (_toCompile) { if (!_toCompile.TryDequeue(out program)) { break; } } if (program.Threaded.Base != null) { ProgramLinkStatus status = program.Threaded.Base.CheckProgramLink(false); if (status != ProgramLinkStatus.Incomplete) { // This program is already compiled. Keep going through the queue. program.Threaded.Compiled = true; i--; continue; } } else { program.Threaded.Base = program.Create(_renderer); } _inProgress.Add(program.Threaded); } }
/// <summary> /// Process a compiled program result. /// </summary> /// <param name="entry">Compiled program entry</param> /// <param name="result">Compilation result</param> /// <param name="asyncCompile">For failed host compilations, indicates if a guest compilation should be done asynchronously</param> private void ProcessCompiledProgram(ref ProgramEntry entry, ProgramLinkStatus result, bool asyncCompile = true) { if (result == ProgramLinkStatus.Success) { // Compilation successful, add to memory cache. if (entry.IsCompute) { _computeCache.Add(entry.CachedProgram); } else { _graphicsCache.Add(entry.CachedProgram); } if (!entry.IsBinary) { _needsHostRegen = true; } _programList.Add(entry.ProgramIndex, entry.CachedProgram); SignalCompiled(); } else if (entry.IsBinary) { // If this is a host binary and compilation failed, // we still have a chance to recompile from the guest binary. CachedShaderProgram program = entry.CachedProgram; if (asyncCompile) { QueueGuestProgram(program.Shaders, program.SpecializationState, entry.ProgramIndex, entry.IsCompute); } else { RecompileFromGuestCode(program.Shaders, program.SpecializationState, entry.ProgramIndex, entry.IsCompute); ProcessCompilationQueue(); } } else { // Failed to compile from both host and guest binary. ErrorCount++; SignalCompiled(); } }
public unsafe Shader(Vk api, Device device, ShaderSource shaderSource) { _api = api; _device = device; Bindings = shaderSource.Bindings; CompileStatus = ProgramLinkStatus.Incomplete; _stage = shaderSource.Stage.Convert(); _entryPointName = Marshal.StringToHGlobalAnsi("main"); CompileTask = Task.Run(() => { byte[] spirv = shaderSource.BinaryCode; if (spirv == null) { spirv = GlslToSpirv(shaderSource.Code, shaderSource.Stage); if (spirv == null) { CompileStatus = ProgramLinkStatus.Failure; return; } } fixed(byte *pCode = spirv) { var shaderModuleCreateInfo = new ShaderModuleCreateInfo() { SType = StructureType.ShaderModuleCreateInfo, CodeSize = (uint)spirv.Length, PCode = (uint *)pCode }; api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError(); } CompileStatus = ProgramLinkStatus.Success; }); }
/// <summary> /// Check the state of programs that have already been compiled, /// and add to the cache if the compilation was successful. /// </summary> public void CheckCompilation() { ProcessCompilationQueue(); // Process programs that already finished compiling. // If not yet compiled, do nothing. This avoids blocking to wait for shader compilation. while (_validationQueue.TryPeek(out ProgramEntry entry)) { ProgramLinkStatus result = entry.HostProgram.CheckProgramLink(false); if (result != ProgramLinkStatus.Incomplete) { ProcessCompiledProgram(ref entry, result); _validationQueue.Dequeue(); } else { break; } } }
public ProgramLinkStatus CheckProgramLink(bool blocking) { if (!blocking && HwCapabilities.SupportsParallelShaderCompile) { GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed); if (completed == 0) { return(ProgramLinkStatus.Incomplete); } } GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status); if (_shaders != null) { for (int index = 0; index < _shaders.Length; index++) { int shaderHandle = ((Shader)_shaders[index]).Handle; GL.DetachShader(Handle, shaderHandle); } _shaders = null; } if (status == 0) { // Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log. _status = ProgramLinkStatus.Failure; Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed."); } else { _status = ProgramLinkStatus.Success; } return(_status); }
/// <summary> /// Check the completion status of the shader compile task, and run callbacks on step completion. /// Calling this periodically is required to progress through steps of the compilation. /// </summary> /// <returns>True if the task is complete, false if it is in progress</returns> public bool IsDone() { if (_compiling) { ProgramLinkStatus status = _program.CheckProgramLink(false); if (status != ProgramLinkStatus.Incomplete) { return(_action(status == ProgramLinkStatus.Success, this)); } } else { // Waiting on the task. if (_programsTask.IsCompleted) { return(_action(true, this)); } } return(false); }
public unsafe Shader(Vk api, Device device, ShaderStage stage, ShaderBindings bindings, byte[] spirv) { _api = api; _device = device; Bindings = bindings; CompileStatus = ProgramLinkStatus.Success; fixed(byte *pCode = spirv) { var shaderModuleCreateInfo = new ShaderModuleCreateInfo() { SType = StructureType.ShaderModuleCreateInfo, CodeSize = (uint)spirv.Length, PCode = (uint *)pCode }; api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError(); } _stage = stage.Convert(); _entryPointName = Marshal.StringToHGlobalAnsi("main"); }
/// <summary> /// Processes the queue of shaders that must save their binaries to the disk cache. /// </summary> public void ProcessShaderCacheQueue() { // Check to see if the binaries for previously compiled shaders are ready, and save them out. while (_programsToSaveQueue.TryPeek(out ProgramToSave programToSave)) { ProgramLinkStatus result = programToSave.HostProgram.CheckProgramLink(false); if (result != ProgramLinkStatus.Incomplete) { if (result == ProgramLinkStatus.Success) { _cacheWriter.AddShader(programToSave.CachedProgram, programToSave.HostProgram.GetBinary()); } _programsToSaveQueue.Dequeue(); } else { break; } } }
public unsafe Shader(Vk api, Device device, ShaderStage stage, ShaderBindings bindings, string glsl) { _api = api; _device = device; _stage = stage.Convert(); _entryPointName = Marshal.StringToHGlobalAnsi("main"); Bindings = bindings; _compileTask = Task.Run(() => { glsl = glsl.Replace("gl_VertexID", "(gl_VertexIndex - gl_BaseVertex)"); glsl = glsl.Replace("gl_InstanceID", "(gl_InstanceIndex - gl_BaseInstance)"); glsl = glsl.Replace("gl_SubGroupInvocationARB", "gl_SubgroupInvocationID"); glsl = glsl.Replace("unpackUint2x32(gl_SubGroupEqMaskARB).x", "gl_SubgroupEqMask.x"); glsl = glsl.Replace("unpackUint2x32(gl_SubGroupGeMaskARB).x", "gl_SubgroupGeMask.x"); glsl = glsl.Replace("unpackUint2x32(gl_SubGroupGtMaskARB).x", "gl_SubgroupGtMask.x"); glsl = glsl.Replace("unpackUint2x32(gl_SubGroupLeMaskARB).x", "gl_SubgroupLeMask.x"); glsl = glsl.Replace("unpackUint2x32(gl_SubGroupLtMaskARB).x", "gl_SubgroupLtMask.x"); glsl = glsl.Replace("unpackUint2x32(ballotARB", "(subgroupBallot"); glsl = glsl.Replace("readInvocationARB", "subgroupBroadcast"); glsl = glsl.Replace("#extension GL_ARB_shader_ballot : enable", "#extension GL_KHR_shader_subgroup_basic : enable\n#extension GL_KHR_shader_subgroup_ballot : enable"); // System.Console.WriteLine(glsl); Options options; lock (_shaderOptionsLock) { options = new Options(false) { SourceLanguage = SourceLanguage.Glsl, TargetSpirVVersion = new SpirVVersion(1, 5) }; } options.SetTargetEnvironment(TargetEnvironment.Vulkan, EnvironmentVersion.Vulkan_1_2); Compiler compiler = new Compiler(options); var scr = compiler.Compile(glsl, "Ryu", GetShaderCShaderStage(stage)); lock (_shaderOptionsLock) { options.Dispose(); } if (scr.Status != Status.Success) { Logger.Error?.Print(LogClass.Gpu, $"Shader compilation error: {scr.Status} {scr.ErrorMessage}"); CompileStatus = ProgramLinkStatus.Failure; return; } var spirvBytes = new Span <byte>((void *)scr.CodePointer, (int)scr.CodeLength); uint[] code = new uint[(scr.CodeLength + 3) / 4]; spirvBytes.CopyTo(MemoryMarshal.Cast <uint, byte>(new Span <uint>(code)).Slice(0, (int)scr.CodeLength)); fixed(uint *pCode = code) { var shaderModuleCreateInfo = new ShaderModuleCreateInfo() { SType = StructureType.ShaderModuleCreateInfo, CodeSize = scr.CodeLength, PCode = pCode }; api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError(); } CompileStatus = ProgramLinkStatus.Success; }); }
public static void Run(ref ProgramCheckLinkCommand command, ThreadedRenderer threaded, IRenderer renderer) { ProgramLinkStatus result = command._program.Get(threaded).Base.CheckProgramLink(command._blocking); command._result.Get(threaded).Result = result; }
public ShaderCollection( VulkanGraphicsDevice gd, Device device, IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) { _gd = gd; _device = device; _shaders = shaders; gd.Shaders.Add(this); var internalShaders = new Shader[shaders.Length]; _infos = new PipelineShaderStageCreateInfo[shaders.Length]; LinkStatus = ProgramLinkStatus.Success; uint stages = 0; for (int i = 0; i < shaders.Length; i++) { var shader = (Shader)shaders[i]; if (!shader.Valid) { LinkStatus = ProgramLinkStatus.Failure; } stages |= 1u << shader.StageFlags switch { ShaderStageFlags.ShaderStageFragmentBit => 1, ShaderStageFlags.ShaderStageGeometryBit => 2, ShaderStageFlags.ShaderStageTessellationControlBit => 3, ShaderStageFlags.ShaderStageTessellationEvaluationBit => 4, _ => 0 }; internalShaders[i] = shader; _infos[i] = internalShaders[i].GetInfo(); } _plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, stages); Stages = stages; int[][] GrabAll(Func <ShaderBindings, IReadOnlyCollection <int> > selector) { bool hasAny = false; int[][] bindings = new int[internalShaders.Length][]; for (int i = 0; i < internalShaders.Length; i++) { var collection = selector(internalShaders[i].Bindings); hasAny |= collection.Count != 0; bindings[i] = collection.ToArray(); } return(hasAny ? bindings : Array.Empty <int[]>()); } Bindings = new[] { GrabAll(x => x.UniformBufferBindings), GrabAll(x => x.StorageBufferBindings), GrabAll(x => x.TextureBindings), GrabAll(x => x.ImageBindings), GrabAll(x => x.BufferTextureBindings), GrabAll(x => x.BufferImageBindings) }; }