Example #1
0
        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;
            }
        }
Example #2
0
        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);
        }
Example #3
0
        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;
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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();
            }
        }
Example #7
0
        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;
                }
            }
        }
Example #9
0
        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);
        }
Example #10
0
        /// <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);
        }
Example #11
0
        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");
        }
Example #12
0
        /// <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;
                }
            }
        }
Example #13
0
        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;
        }
Example #15
0
        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)
            };
        }