/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // the shaders and the pipelines of the vulkan renderer. // // a shader of shaders/vk14 is taken from the SPIR-V binary of shaders/vk14bin when there's an up to date one // (gfx.shaders.binaries), from the cache of the shaders compiled before (cache/vulkan14/shaders in the directory of the user, // keyed by the source with its includes, the variant and the version of glslang), or compiled now by glslang and put in the // cache. the pipelines are made from a description of what isn't dynamic (the shaders, the layout of the vertices, the class // of the primitives, the blending, the formats of the attachments, the samples); the rest of the state is dynamic. the // VkPipelineCache is read from and written to the directory of the user, and thrown away when it comes from another device // or driver. no VkShaderModule: the code goes to the stages of the pipelines (maintenance5). // // both libraries may be asked from any thread (the stage M5 of the plan: the pipelines of the scene made by the background // threads): their maps are guarded, the shaders are compiled and the pipelines made outside of the locks (the VkPipelineCache // is synchronized by vulkan) #pragma once #include "rendering/vulkan14/vulkan14common.h" #include "rendering/common/shadersource.h" #include #include #include namespace vk14 { class device; // the SPIR-V of a shader, and what its source says (the material directives) struct shader_code { gfx::shader_source source; VkShaderStageFlagBits stage{VK_SHADER_STAGE_VERTEX_BIT}; std::vector spirv; // where it came from: "binary", "cache", "compiled" char const *origin{""}; // what it was asked for by (shader_library::get()), for the list of the pipelines made in a session std::string name; std::string defines; }; class shader_library { public: shader_library() = default; shader_library(shader_library const &) = delete; shader_library &operator=(shader_library const &) = delete; ~shader_library(); // Preamble: what the renderer puts after #version (the constants of vulkan14bindings.h) bool init(std::string const &Preamble, std::string &Reason); void shutdown(); // the shader of shaders/vk14 (Defines: the variant). throws gfx::shader_exception std::shared_ptr get(std::string const &Name, std::string const &Defines = {}); // the shader, when it was got before; nothing is loaded or compiled std::shared_ptr find(std::string const &Name, std::string const &Defines = {}) const; // what was loaded from where, for the debug panel std::string info() const; private: std::vector compile(gfx::shader_source const &Source) const; mutable std::mutex m_mutex; std::string m_preamble; std::string m_cachedir; std::string m_compilerversion; bool m_glslang{false}; bool m_binaries{false}; std::unordered_map> m_shaders; int m_frombinary{0}; int m_fromcache{0}; int m_compiled{0}; }; // how the colour of a pipeline is mixed with what is there enum class blend_mode { none, alpha, // the colour over what is there by its alpha, the alpha kept for what's behind (the user interface) premultiplied, additive, // the blending of the scene, as glBlendFunc() of the opengl renderer gives it to the colour and the alpha alike scene_alpha, // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA scene_additive, // GL_SRC_ALPHA, GL_ONE (the glare of the lamps) under_transmittance, // GL_ONE, GL_SRC_ALPHA: the colour added, what is there kept by the alpha (the clouds and the fog over the sky) multiply, // GL_ZERO, GL_SRC_COLOR: what is there times the colour (the ambient occlusion) no_colour // the colour isn't written, only the depth (the depth prepass of the instances inside the colour pass) }; struct vertex_layout { std::vector bindings; std::vector attributes; }; // what a pipeline is made of; the rest of the state is set while drawing (vk14::set_draw_state()) struct pipeline_desc { std::vector> stages; VkPipelineLayout layout{VK_NULL_HANDLE}; vertex_layout vertices; // the class of the primitives; the primitive itself is dynamic VkPrimitiveTopology topology{VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST}; blend_mode blending{blend_mode::none}; std::vector colour_formats; VkFormat depth_format{VK_FORMAT_UNDEFINED}; VkSampleCountFlagBits samples{VK_SAMPLE_COUNT_1_BIT}; // the views drawn at once (multiview, the cube shadow maps of the lamps), 0: none std::uint32_t view_mask{0}; // the values of the specialization constants 0, 1, 2 ... of all the stages std::vector specialization; std::string name; }; class pipeline_library { public: pipeline_library() = default; pipeline_library(pipeline_library const &) = delete; pipeline_library &operator=(pipeline_library const &) = delete; ~pipeline_library(); bool init(device const &Device, std::string &Reason); // writes the pipeline cache to the disk and destroys the pipelines void shutdown(); // the pipeline of the description, made at the first call (from the cache on the disk, when it has it). null when it can't be made VkPipeline get(pipeline_desc const &Desc); // the pipeline of the description when it was made already (Pipeline: it, null when it couldn't be); false: not made yet bool find(pipeline_desc const &Desc, VkPipeline &Pipeline) const; VkPipeline compute(std::shared_ptr const &Shader, VkPipelineLayout Layout, std::vector const &Specialization = {}, std::string const &Name = {}); std::string info() const; private: std::uint64_t key_of(pipeline_desc const &Desc) const; // the pipeline made for the key by another thread meanwhile is kept, the one of the caller destroyed VkPipeline keep(std::uint64_t Key, VkPipeline Pipeline, double Milliseconds); mutable std::mutex m_mutex; device const *m_device{nullptr}; VkPipelineCache m_cache{VK_NULL_HANDLE}; std::string m_cachepath; std::unordered_map m_pipelines; double m_creationms{0.0}; }; // the dynamic state of a pipeline in its plain form: the whole of Extent, no culling, no depth, triangles void set_draw_state(command_stream *Commands, VkExtent2D Extent); } // namespace vk14