1 /* Copyright (c) 2017-2018 Hans-Kristian Arntzen 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be 12 * included in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #pragma once 24 25 #include "cookie.hpp" 26 #include "descriptor_set.hpp" 27 #include "hash.hpp" 28 #include "intrusive.hpp" 29 #include "limits.hpp" 30 #include "vulkan.hpp" 31 #include "enum_cast.hpp" 32 33 namespace Vulkan 34 { 35 class Device; 36 37 enum class ShaderStage 38 { 39 Vertex = 0, 40 TessControl = 1, 41 TessEvaluation = 2, 42 Geometry = 3, 43 Fragment = 4, 44 Compute = 5, 45 Count 46 }; 47 48 struct ResourceLayout 49 { 50 uint32_t input_mask = 0; 51 uint32_t output_mask = 0; 52 uint32_t push_constant_size = 0; 53 uint32_t spec_constant_mask = 0; 54 DescriptorSetLayout sets[VULKAN_NUM_DESCRIPTOR_SETS]; 55 }; 56 57 struct CombinedResourceLayout 58 { 59 uint32_t attribute_mask = 0; 60 uint32_t render_target_mask = 0; 61 DescriptorSetLayout sets[VULKAN_NUM_DESCRIPTOR_SETS] = {}; 62 uint32_t stages_for_bindings[VULKAN_NUM_DESCRIPTOR_SETS][VULKAN_NUM_BINDINGS] = {}; 63 uint32_t stages_for_sets[VULKAN_NUM_DESCRIPTOR_SETS] = {}; 64 VkPushConstantRange push_constant_range = {}; 65 uint32_t descriptor_set_mask = 0; 66 uint32_t spec_constant_mask[Util::ecast(ShaderStage::Count)] = {}; 67 uint32_t combined_spec_constant_mask = 0; 68 Util::Hash push_constant_layout_hash = 0; 69 }; 70 71 class PipelineLayout : public HashedObject<PipelineLayout> 72 { 73 public: 74 PipelineLayout(Util::Hash hash, Device *device, const CombinedResourceLayout &layout); 75 ~PipelineLayout(); 76 get_resource_layout() const77 const CombinedResourceLayout &get_resource_layout() const 78 { 79 return layout; 80 } 81 get_layout() const82 VkPipelineLayout get_layout() const 83 { 84 return pipe_layout; 85 } 86 get_allocator(unsigned set) const87 DescriptorSetAllocator *get_allocator(unsigned set) const 88 { 89 return set_allocators[set]; 90 } 91 92 private: 93 Device *device; 94 VkPipelineLayout pipe_layout = VK_NULL_HANDLE; 95 CombinedResourceLayout layout; 96 DescriptorSetAllocator *set_allocators[VULKAN_NUM_DESCRIPTOR_SETS] = {}; 97 }; 98 99 class Shader : public HashedObject<Shader> 100 { 101 public: 102 Shader(Util::Hash hash, Device *device, const uint32_t *data, size_t size); 103 ~Shader(); 104 get_layout() const105 const ResourceLayout &get_layout() const 106 { 107 return layout; 108 } 109 get_module() const110 VkShaderModule get_module() const 111 { 112 return module; 113 } 114 115 static const char *stage_to_name(ShaderStage stage); 116 117 private: 118 Device *device; 119 VkShaderModule module; 120 ResourceLayout layout; 121 }; 122 123 class Program : public HashedObject<Program>, public InternalSyncEnabled 124 { 125 public: 126 Program(Device *device, Shader *vertex, Shader *fragment); 127 Program(Device *device, Shader *compute); 128 ~Program(); 129 get_shader(ShaderStage stage) const130 inline const Shader *get_shader(ShaderStage stage) const 131 { 132 return shaders[Util::ecast(stage)]; 133 } 134 set_pipeline_layout(PipelineLayout * new_layout)135 void set_pipeline_layout(PipelineLayout *new_layout) 136 { 137 layout = new_layout; 138 } 139 get_pipeline_layout() const140 PipelineLayout *get_pipeline_layout() const 141 { 142 return layout; 143 } 144 145 VkPipeline get_pipeline(Util::Hash hash) const; 146 VkPipeline add_pipeline(Util::Hash hash, VkPipeline pipeline); 147 148 private: 149 void set_shader(ShaderStage stage, Shader *handle); 150 Device *device; 151 Shader *shaders[Util::ecast(ShaderStage::Count)] = {}; 152 PipelineLayout *layout = nullptr; 153 VulkanCache<Util::IntrusivePODWrapper<VkPipeline>> pipelines; 154 }; 155 } 156