1 // Copyright 2018 The Amber Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SRC_PIPELINE_H_ 16 #define SRC_PIPELINE_H_ 17 18 #include <map> 19 #include <memory> 20 #include <string> 21 #include <unordered_map> 22 #include <utility> 23 #include <vector> 24 25 #include "amber/result.h" 26 #include "src/buffer.h" 27 #include "src/command_data.h" 28 #include "src/pipeline_data.h" 29 #include "src/sampler.h" 30 #include "src/shader.h" 31 32 namespace amber { 33 34 enum class PipelineType { kCompute = 0, kGraphics }; 35 36 /// Stores all information related to a pipeline. 37 class Pipeline { 38 public: 39 /// Information on a shader attached to this pipeline. 40 class ShaderInfo { 41 public: 42 ShaderInfo(Shader*, ShaderType type); 43 ShaderInfo(const ShaderInfo&); 44 ~ShaderInfo(); 45 46 ShaderInfo& operator=(const ShaderInfo&) = default; 47 48 // Set the optimization options for this shader. Optimizations are 49 // specified like command-line arguments to spirv-opt (see its --help). 50 // Parsing is done by spvtools::Optimizer::RegisterPassesFromFlags (see 51 // SPIRV-Tools include/spirv-tools/optimizer.hpp). SetShaderOptimizations(const std::vector<std::string> & opts)52 void SetShaderOptimizations(const std::vector<std::string>& opts) { 53 shader_optimizations_ = opts; 54 } GetShaderOptimizations()55 const std::vector<std::string>& GetShaderOptimizations() const { 56 return shader_optimizations_; 57 } 58 SetCompileOptions(const std::vector<std::string> & options)59 void SetCompileOptions(const std::vector<std::string>& options) { 60 compile_options_ = options; 61 } GetCompileOptions()62 const std::vector<std::string>& GetCompileOptions() const { 63 return compile_options_; 64 } 65 66 enum class RequiredSubgroupSizeSetting : uint32_t { 67 kNotSet = 0, 68 kSetToSpecificSize, 69 kSetToMinimumSize, 70 kSetToMaximumSize 71 }; 72 SetRequiredSubgroupSizeSetting(RequiredSubgroupSizeSetting setting,uint32_t size)73 void SetRequiredSubgroupSizeSetting(RequiredSubgroupSizeSetting setting, 74 uint32_t size) { 75 required_subgroup_size_setting_ = setting; 76 required_subgroup_size_ = size; 77 } GetRequiredSubgroupSizeSetting()78 RequiredSubgroupSizeSetting GetRequiredSubgroupSizeSetting() const { 79 return required_subgroup_size_setting_; 80 } GetRequiredSubgroupSize()81 uint32_t GetRequiredSubgroupSize() const { return required_subgroup_size_; } 82 SetVaryingSubgroupSize(const bool isSet)83 void SetVaryingSubgroupSize(const bool isSet) { 84 varying_subgroup_size_ = isSet; 85 } GetVaryingSubgroupSize()86 bool GetVaryingSubgroupSize() const { return varying_subgroup_size_; } 87 SetRequireFullSubgroups(const bool isSet)88 void SetRequireFullSubgroups(const bool isSet) { 89 require_full_subgroups_ = isSet; 90 } GetRequireFullSubgroups()91 bool GetRequireFullSubgroups() const { return require_full_subgroups_; } 92 SetEmitDebugInfo(const bool isSet)93 void SetEmitDebugInfo(const bool isSet) { emit_debug_info_ = isSet; } GetEmitDebugInfo()94 bool GetEmitDebugInfo() const { return emit_debug_info_; } 95 SetShader(Shader * shader)96 void SetShader(Shader* shader) { shader_ = shader; } GetShader()97 const Shader* GetShader() const { return shader_; } 98 SetEntryPoint(const std::string & ep)99 void SetEntryPoint(const std::string& ep) { entry_point_ = ep; } GetEntryPoint()100 const std::string& GetEntryPoint() const { return entry_point_; } 101 SetShaderType(ShaderType type)102 void SetShaderType(ShaderType type) { shader_type_ = type; } GetShaderType()103 ShaderType GetShaderType() const { return shader_type_; } 104 GetData()105 const std::vector<uint32_t> GetData() const { return data_; } SetData(std::vector<uint32_t> && data)106 void SetData(std::vector<uint32_t>&& data) { data_ = std::move(data); } 107 GetSpecialization()108 const std::map<uint32_t, uint32_t>& GetSpecialization() const { 109 return specialization_; 110 } AddSpecialization(uint32_t spec_id,uint32_t value)111 void AddSpecialization(uint32_t spec_id, uint32_t value) { 112 specialization_[spec_id] = value; 113 } 114 115 /// Descriptor information for an OpenCL-C shader. 116 struct DescriptorMapEntry { 117 std::string arg_name = ""; 118 119 enum class Kind : int { 120 UNKNOWN, 121 SSBO, 122 UBO, 123 POD, 124 POD_UBO, 125 POD_PUSHCONSTANT, 126 RO_IMAGE, 127 WO_IMAGE, 128 SAMPLER, 129 } kind; 130 131 uint32_t descriptor_set = 0; 132 uint32_t binding = 0; 133 uint32_t arg_ordinal = 0; 134 uint32_t pod_offset = 0; 135 uint32_t pod_arg_size = 0; 136 }; 137 AddDescriptorEntry(const std::string & kernel,DescriptorMapEntry && entry)138 void AddDescriptorEntry(const std::string& kernel, 139 DescriptorMapEntry&& entry) { 140 descriptor_map_[kernel].emplace_back(std::move(entry)); 141 } 142 const std::unordered_map<std::string, std::vector<DescriptorMapEntry>>& GetDescriptorMap()143 GetDescriptorMap() const { 144 return descriptor_map_; 145 } 146 147 /// Push constant information for an OpenCL-C shader. 148 struct PushConstant { 149 enum class PushConstantType { 150 kDimensions = 0, 151 kGlobalOffset, 152 kRegionOffset, 153 }; 154 PushConstantType type; 155 uint32_t offset = 0; 156 uint32_t size = 0; 157 }; 158 AddPushConstant(PushConstant && pc)159 void AddPushConstant(PushConstant&& pc) { 160 push_constants_.emplace_back(std::move(pc)); 161 } GetPushConstants()162 const std::vector<PushConstant>& GetPushConstants() const { 163 return push_constants_; 164 } 165 166 private: 167 Shader* shader_ = nullptr; 168 ShaderType shader_type_; 169 std::vector<std::string> shader_optimizations_; 170 std::string entry_point_; 171 std::vector<uint32_t> data_; 172 std::map<uint32_t, uint32_t> specialization_; 173 std::unordered_map<std::string, std::vector<DescriptorMapEntry>> 174 descriptor_map_; 175 std::vector<PushConstant> push_constants_; 176 std::vector<std::string> compile_options_; 177 RequiredSubgroupSizeSetting required_subgroup_size_setting_; 178 uint32_t required_subgroup_size_; 179 bool varying_subgroup_size_; 180 bool require_full_subgroups_; 181 bool emit_debug_info_; 182 }; 183 184 /// Information on a buffer attached to the pipeline. 185 /// 186 /// The BufferInfo will have either (descriptor_set, binding) or location 187 /// attached. 188 struct BufferInfo { 189 BufferInfo() = default; BufferInfoBufferInfo190 explicit BufferInfo(Buffer* buf) : buffer(buf) {} 191 192 Buffer* buffer = nullptr; 193 uint32_t descriptor_set = 0; 194 uint32_t binding = 0; 195 uint32_t location = 0; 196 uint32_t base_mip_level = 0; 197 uint32_t dynamic_offset = 0; 198 std::string arg_name = ""; 199 uint32_t arg_no = 0; 200 BufferType type = BufferType::kUnknown; 201 InputRate input_rate = InputRate::kVertex; 202 Format* format; 203 uint32_t offset = 0; 204 uint32_t stride = 0; 205 Sampler* sampler = nullptr; 206 }; 207 208 /// Information on a sampler attached to the pipeline. 209 struct SamplerInfo { 210 SamplerInfo() = default; SamplerInfoSamplerInfo211 explicit SamplerInfo(Sampler* samp) : sampler(samp) {} 212 213 Sampler* sampler = nullptr; 214 uint32_t descriptor_set = 0; 215 uint32_t binding = 0; 216 std::string arg_name = ""; 217 uint32_t arg_no = 0; 218 uint32_t mask = 0; 219 }; 220 221 static const char* kGeneratedColorBuffer; 222 static const char* kGeneratedDepthBuffer; 223 static const char* kGeneratedPushConstantBuffer; 224 225 explicit Pipeline(PipelineType type); 226 ~Pipeline(); 227 228 std::unique_ptr<Pipeline> Clone() const; 229 IsGraphics()230 bool IsGraphics() const { return pipeline_type_ == PipelineType::kGraphics; } IsCompute()231 bool IsCompute() const { return pipeline_type_ == PipelineType::kCompute; } 232 GetType()233 PipelineType GetType() const { return pipeline_type_; } 234 SetName(const std::string & name)235 void SetName(const std::string& name) { name_ = name; } GetName()236 const std::string& GetName() const { return name_; } 237 SetFramebufferWidth(uint32_t fb_width)238 void SetFramebufferWidth(uint32_t fb_width) { 239 fb_width_ = fb_width; 240 UpdateFramebufferSizes(); 241 } GetFramebufferWidth()242 uint32_t GetFramebufferWidth() const { return fb_width_; } 243 SetFramebufferHeight(uint32_t fb_height)244 void SetFramebufferHeight(uint32_t fb_height) { 245 fb_height_ = fb_height; 246 UpdateFramebufferSizes(); 247 } GetFramebufferHeight()248 uint32_t GetFramebufferHeight() const { return fb_height_; } 249 250 /// Adds |shader| of |type| to the pipeline. 251 Result AddShader(Shader* shader, ShaderType type); 252 /// Returns information on all bound shaders in this pipeline. GetShaders()253 std::vector<ShaderInfo>& GetShaders() { return shaders_; } 254 /// Returns information on all bound shaders in this pipeline. GetShaders()255 const std::vector<ShaderInfo>& GetShaders() const { return shaders_; } 256 257 /// Returns the ShaderInfo for |shader| or nullptr. GetShader(Shader * shader)258 const ShaderInfo* GetShader(Shader* shader) const { 259 for (const auto& info : shaders_) { 260 if (info.GetShader() == shader) 261 return &info; 262 } 263 return nullptr; 264 } 265 266 /// Sets the |type| of |shader| in the pipeline. 267 Result SetShaderType(const Shader* shader, ShaderType type); 268 /// Sets the entry point |name| for |shader| in this pipeline. 269 Result SetShaderEntryPoint(const Shader* shader, const std::string& name); 270 /// Sets the optimizations (|opts|) for |shader| in this pipeline. 271 Result SetShaderOptimizations(const Shader* shader, 272 const std::vector<std::string>& opts); 273 /// Sets the compile options for |shader| in this pipeline. 274 Result SetShaderCompileOptions(const Shader* shader, 275 const std::vector<std::string>& options); 276 /// Sets required subgroup size. 277 Result SetShaderRequiredSubgroupSize(const Shader* shader, 278 const uint32_t subgroupSize); 279 /// Sets required subgroup size to the device minimum supported subgroup size. 280 Result SetShaderRequiredSubgroupSizeToMinimum(const Shader* shader); 281 282 /// Sets required subgroup size to the device maximum supported subgroup size. 283 Result SetShaderRequiredSubgroupSizeToMaximum(const Shader* shader); 284 285 /// Sets varying subgroup size property. 286 Result SetShaderVaryingSubgroupSize(const Shader* shader, const bool isSet); 287 288 /// Sets require full subgroups property. 289 Result SetShaderRequireFullSubgroups(const Shader* shader, const bool isSet); 290 /// Returns a list of all colour attachments in this pipeline. GetColorAttachments()291 const std::vector<BufferInfo>& GetColorAttachments() const { 292 return color_attachments_; 293 } 294 /// Adds |buf| as a colour attachment at |location| in the pipeline. 295 /// Uses |base_mip_level| as the mip level for output. 296 Result AddColorAttachment(Buffer* buf, 297 uint32_t location, 298 uint32_t base_mip_level); 299 /// Retrieves the location that |buf| is bound to in the pipeline. The 300 /// location will be written to |loc|. An error result will be return if 301 /// something goes wrong. 302 Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; 303 304 /// Sets |buf| as the depth/stencil buffer for this pipeline. 305 Result SetDepthStencilBuffer(Buffer* buf); 306 /// Returns information on the depth/stencil buffer bound to the pipeline. If 307 /// no depth buffer is bound the |BufferInfo::buffer| parameter will be 308 /// nullptr. GetDepthStencilBuffer()309 const BufferInfo& GetDepthStencilBuffer() const { 310 return depth_stencil_buffer_; 311 } 312 313 /// Returns pipeline data. GetPipelineData()314 PipelineData* GetPipelineData() { return &pipeline_data_; } 315 316 /// Returns information on all vertex buffers bound to the pipeline. GetVertexBuffers()317 const std::vector<BufferInfo>& GetVertexBuffers() const { 318 return vertex_buffers_; 319 } 320 /// Adds |buf| as a vertex buffer at |location| in the pipeline using |rate| 321 /// as the input rate, |format| as vertex data format, |offset| as a starting 322 /// offset for the vertex buffer data, and |stride| for the data stride in 323 /// bytes. 324 Result AddVertexBuffer(Buffer* buf, 325 uint32_t location, 326 InputRate rate, 327 Format* format, 328 uint32_t offset, 329 uint32_t stride); 330 331 /// Binds |buf| as the index buffer for this pipeline. 332 Result SetIndexBuffer(Buffer* buf); 333 /// Returns the index buffer bound to this pipeline or nullptr if no index 334 /// buffer bound. GetIndexBuffer()335 Buffer* GetIndexBuffer() const { return index_buffer_; } 336 337 /// Adds |buf| of |type| to the pipeline at the given |descriptor_set|, 338 /// |binding|, |base_mip_level|, and |dynamic_offset|. 339 void AddBuffer(Buffer* buf, 340 BufferType type, 341 uint32_t descriptor_set, 342 uint32_t binding, 343 uint32_t base_mip_level, 344 uint32_t dynamic_offset); 345 /// Adds |buf| to the pipeline at the given |arg_name|. 346 void AddBuffer(Buffer* buf, BufferType type, const std::string& arg_name); 347 /// Adds |buf| to the pipeline at the given |arg_no|. 348 void AddBuffer(Buffer* buf, BufferType type, uint32_t arg_no); 349 /// Returns information on all buffers in this pipeline. GetBuffers()350 const std::vector<BufferInfo>& GetBuffers() const { return buffers_; } 351 /// Clears all buffer bindings for given |descriptor_set| and |binding|. 352 void ClearBuffers(uint32_t descriptor_set, uint32_t binding); 353 354 /// Adds |sampler| to the pipeline at the given |descriptor_set| and 355 /// |binding|. 356 void AddSampler(Sampler* sampler, uint32_t descriptor_set, uint32_t binding); 357 /// Adds |sampler| to the pipeline at the given |arg_name|. 358 void AddSampler(Sampler* sampler, const std::string& arg_name); 359 /// Adds |sampler| to the pieline at the given |arg_no|. 360 void AddSampler(Sampler* sampler, uint32_t arg_no); 361 /// Adds an entry for an OpenCL literal sampler. 362 void AddSampler(uint32_t sampler_mask, 363 uint32_t descriptor_set, 364 uint32_t binding); 365 /// Clears all sampler bindings for given |descriptor_set| and |binding|. 366 void ClearSamplers(uint32_t descriptor_set, uint32_t binding); 367 368 /// Returns information on all samplers in this pipeline. GetSamplers()369 const std::vector<SamplerInfo>& GetSamplers() const { return samplers_; } 370 371 /// Updates the descriptor set and binding info for the OpenCL-C kernel bound 372 /// to the pipeline. No effect for other shader formats. 373 Result UpdateOpenCLBufferBindings(); 374 375 /// Returns the buffer which is currently bound to this pipeline at 376 /// |descriptor_set| and |binding|. 377 Buffer* GetBufferForBinding(uint32_t descriptor_set, uint32_t binding) const; 378 379 Result SetPushConstantBuffer(Buffer* buf); GetPushConstantBuffer()380 const BufferInfo& GetPushConstantBuffer() const { 381 return push_constant_buffer_; 382 } 383 384 /// Validates that the pipeline has been created correctly. 385 Result Validate() const; 386 387 /// Generates a default color attachment in B8G8R8A8_UNORM. 388 std::unique_ptr<Buffer> GenerateDefaultColorAttachmentBuffer(); 389 /// Generates a default depth/stencil attachment in D32_SFLOAT_S8_UINT format. 390 std::unique_ptr<Buffer> GenerateDefaultDepthStencilAttachmentBuffer(); 391 392 /// Information on values set for OpenCL-C plain-old-data args. 393 struct ArgSetInfo { 394 std::string name; 395 uint32_t ordinal = 0; 396 Format* fmt = nullptr; 397 Value value; 398 }; 399 400 /// Adds value from SET command. SetArg(ArgSetInfo && info)401 void SetArg(ArgSetInfo&& info) { set_arg_values_.push_back(std::move(info)); } SetArgValues()402 const std::vector<ArgSetInfo>& SetArgValues() const { 403 return set_arg_values_; 404 } 405 406 /// Generate the buffers necessary for OpenCL PoD arguments populated via SET 407 /// command. This should be called after all other buffers are bound. 408 Result GenerateOpenCLPodBuffers(); 409 410 /// Generate the samplers necessary for OpenCL literal samplers from the 411 /// descriptor map. This should be called after all other samplers are bound. 412 Result GenerateOpenCLLiteralSamplers(); 413 414 /// Generate the push constant buffers necessary for OpenCL kernels. 415 Result GenerateOpenCLPushConstants(); 416 417 private: 418 void UpdateFramebufferSizes(); 419 420 Result SetShaderRequiredSubgroupSize( 421 const Shader* shader, 422 const ShaderInfo::RequiredSubgroupSizeSetting setting, 423 const uint32_t subgroupSize); 424 425 Result CreatePushConstantBuffer(); 426 427 Result ValidateGraphics() const; 428 Result ValidateCompute() const; 429 430 PipelineType pipeline_type_ = PipelineType::kCompute; 431 std::string name_; 432 std::vector<ShaderInfo> shaders_; 433 std::vector<BufferInfo> color_attachments_; 434 std::vector<BufferInfo> vertex_buffers_; 435 std::vector<BufferInfo> buffers_; 436 std::vector<std::unique_ptr<type::Type>> types_; 437 std::vector<SamplerInfo> samplers_; 438 std::vector<std::unique_ptr<Format>> formats_; 439 BufferInfo depth_stencil_buffer_; 440 BufferInfo push_constant_buffer_; 441 Buffer* index_buffer_ = nullptr; 442 PipelineData pipeline_data_; 443 uint32_t fb_width_ = 250; 444 uint32_t fb_height_ = 250; 445 446 std::vector<ArgSetInfo> set_arg_values_; 447 std::vector<std::unique_ptr<Buffer>> opencl_pod_buffers_; 448 /// Maps (descriptor set, binding) to the buffer for that binding pair. 449 std::map<std::pair<uint32_t, uint32_t>, Buffer*> opencl_pod_buffer_map_; 450 std::vector<std::unique_ptr<Sampler>> opencl_literal_samplers_; 451 std::unique_ptr<Buffer> opencl_push_constants_; 452 }; 453 454 } // namespace amber 455 456 #endif // SRC_PIPELINE_H_ 457