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 SetShader(Shader * shader)93 void SetShader(Shader* shader) { shader_ = shader; } GetShader()94 const Shader* GetShader() const { return shader_; } 95 SetEntryPoint(const std::string & ep)96 void SetEntryPoint(const std::string& ep) { entry_point_ = ep; } GetEntryPoint()97 const std::string& GetEntryPoint() const { return entry_point_; } 98 SetShaderType(ShaderType type)99 void SetShaderType(ShaderType type) { shader_type_ = type; } GetShaderType()100 ShaderType GetShaderType() const { return shader_type_; } 101 GetData()102 const std::vector<uint32_t> GetData() const { return data_; } SetData(std::vector<uint32_t> && data)103 void SetData(std::vector<uint32_t>&& data) { data_ = std::move(data); } 104 GetSpecialization()105 const std::map<uint32_t, uint32_t>& GetSpecialization() const { 106 return specialization_; 107 } AddSpecialization(uint32_t spec_id,uint32_t value)108 void AddSpecialization(uint32_t spec_id, uint32_t value) { 109 specialization_[spec_id] = value; 110 } 111 112 /// Descriptor information for an OpenCL-C shader. 113 struct DescriptorMapEntry { 114 std::string arg_name = ""; 115 116 enum class Kind : int { 117 UNKNOWN, 118 SSBO, 119 UBO, 120 POD, 121 POD_UBO, 122 POD_PUSHCONSTANT, 123 RO_IMAGE, 124 WO_IMAGE, 125 SAMPLER, 126 } kind; 127 128 uint32_t descriptor_set = 0; 129 uint32_t binding = 0; 130 uint32_t arg_ordinal = 0; 131 uint32_t pod_offset = 0; 132 uint32_t pod_arg_size = 0; 133 }; 134 AddDescriptorEntry(const std::string & kernel,DescriptorMapEntry && entry)135 void AddDescriptorEntry(const std::string& kernel, 136 DescriptorMapEntry&& entry) { 137 descriptor_map_[kernel].emplace_back(std::move(entry)); 138 } 139 const std::unordered_map<std::string, std::vector<DescriptorMapEntry>>& GetDescriptorMap()140 GetDescriptorMap() const { 141 return descriptor_map_; 142 } 143 144 /// Push constant information for an OpenCL-C shader. 145 struct PushConstant { 146 enum class PushConstantType { 147 kDimensions = 0, 148 kGlobalOffset, 149 kRegionOffset, 150 }; 151 PushConstantType type; 152 uint32_t offset = 0; 153 uint32_t size = 0; 154 }; 155 AddPushConstant(PushConstant && pc)156 void AddPushConstant(PushConstant&& pc) { 157 push_constants_.emplace_back(std::move(pc)); 158 } GetPushConstants()159 const std::vector<PushConstant>& GetPushConstants() const { 160 return push_constants_; 161 } 162 163 private: 164 Shader* shader_ = nullptr; 165 ShaderType shader_type_; 166 std::vector<std::string> shader_optimizations_; 167 std::string entry_point_; 168 std::vector<uint32_t> data_; 169 std::map<uint32_t, uint32_t> specialization_; 170 std::unordered_map<std::string, std::vector<DescriptorMapEntry>> 171 descriptor_map_; 172 std::vector<PushConstant> push_constants_; 173 std::vector<std::string> compile_options_; 174 RequiredSubgroupSizeSetting required_subgroup_size_setting_; 175 uint32_t required_subgroup_size_; 176 bool varying_subgroup_size_; 177 bool require_full_subgroups_; 178 }; 179 180 /// Information on a buffer attached to the pipeline. 181 /// 182 /// The BufferInfo will have either (descriptor_set, binding) or location 183 /// attached. 184 struct BufferInfo { 185 BufferInfo() = default; BufferInfoBufferInfo186 explicit BufferInfo(Buffer* buf) : buffer(buf) {} 187 188 Buffer* buffer = nullptr; 189 uint32_t descriptor_set = 0; 190 uint32_t binding = 0; 191 uint32_t location = 0; 192 uint32_t base_mip_level = 0; 193 uint32_t dynamic_offset = 0; 194 std::string arg_name = ""; 195 uint32_t arg_no = 0; 196 BufferType type = BufferType::kUnknown; 197 InputRate input_rate = InputRate::kVertex; 198 Format* format; 199 uint32_t offset = 0; 200 uint32_t stride = 0; 201 Sampler* sampler = nullptr; 202 uint64_t descriptor_offset = 0; 203 uint64_t descriptor_range = ~0ULL; // ~0ULL == VK_WHOLE_SIZE 204 }; 205 206 /// Information on a sampler attached to the pipeline. 207 struct SamplerInfo { 208 SamplerInfo() = default; SamplerInfoSamplerInfo209 explicit SamplerInfo(Sampler* samp) : sampler(samp) {} 210 211 Sampler* sampler = nullptr; 212 uint32_t descriptor_set = 0; 213 uint32_t binding = 0; 214 std::string arg_name = ""; 215 uint32_t arg_no = 0; 216 uint32_t mask = 0; 217 }; 218 219 static const char* kGeneratedColorBuffer; 220 static const char* kGeneratedDepthBuffer; 221 static const char* kGeneratedPushConstantBuffer; 222 223 explicit Pipeline(PipelineType type); 224 ~Pipeline(); 225 226 std::unique_ptr<Pipeline> Clone() const; 227 IsGraphics()228 bool IsGraphics() const { return pipeline_type_ == PipelineType::kGraphics; } IsCompute()229 bool IsCompute() const { return pipeline_type_ == PipelineType::kCompute; } 230 GetType()231 PipelineType GetType() const { return pipeline_type_; } 232 SetName(const std::string & name)233 void SetName(const std::string& name) { name_ = name; } GetName()234 const std::string& GetName() const { return name_; } 235 SetFramebufferWidth(uint32_t fb_width)236 void SetFramebufferWidth(uint32_t fb_width) { 237 fb_width_ = fb_width; 238 UpdateFramebufferSizes(); 239 } GetFramebufferWidth()240 uint32_t GetFramebufferWidth() const { return fb_width_; } 241 SetFramebufferHeight(uint32_t fb_height)242 void SetFramebufferHeight(uint32_t fb_height) { 243 fb_height_ = fb_height; 244 UpdateFramebufferSizes(); 245 } GetFramebufferHeight()246 uint32_t GetFramebufferHeight() const { return fb_height_; } 247 248 /// Adds |shader| of |type| to the pipeline. 249 Result AddShader(Shader* shader, ShaderType type); 250 /// Returns information on all bound shaders in this pipeline. GetShaders()251 std::vector<ShaderInfo>& GetShaders() { return shaders_; } 252 /// Returns information on all bound shaders in this pipeline. GetShaders()253 const std::vector<ShaderInfo>& GetShaders() const { return shaders_; } 254 255 /// Returns the ShaderInfo for |shader| or nullptr. GetShader(Shader * shader)256 const ShaderInfo* GetShader(Shader* shader) const { 257 for (const auto& info : shaders_) { 258 if (info.GetShader() == shader) 259 return &info; 260 } 261 return nullptr; 262 } 263 264 /// Sets the |type| of |shader| in the pipeline. 265 Result SetShaderType(const Shader* shader, ShaderType type); 266 /// Sets the entry point |name| for |shader| in this pipeline. 267 Result SetShaderEntryPoint(const Shader* shader, const std::string& name); 268 /// Sets the optimizations (|opts|) for |shader| in this pipeline. 269 Result SetShaderOptimizations(const Shader* shader, 270 const std::vector<std::string>& opts); 271 /// Sets the compile options for |shader| in this pipeline. 272 Result SetShaderCompileOptions(const Shader* shader, 273 const std::vector<std::string>& options); 274 /// Sets required subgroup size. 275 Result SetShaderRequiredSubgroupSize(const Shader* shader, 276 const uint32_t subgroupSize); 277 /// Sets required subgroup size to the device minimum supported subgroup size. 278 Result SetShaderRequiredSubgroupSizeToMinimum(const Shader* shader); 279 280 /// Sets required subgroup size to the device maximum supported subgroup size. 281 Result SetShaderRequiredSubgroupSizeToMaximum(const Shader* shader); 282 283 /// Sets varying subgroup size property. 284 Result SetShaderVaryingSubgroupSize(const Shader* shader, const bool isSet); 285 286 /// Sets require full subgroups property. 287 Result SetShaderRequireFullSubgroups(const Shader* shader, const bool isSet); 288 /// Returns a list of all colour attachments in this pipeline. GetColorAttachments()289 const std::vector<BufferInfo>& GetColorAttachments() const { 290 return color_attachments_; 291 } 292 /// Adds |buf| as a colour attachment at |location| in the pipeline. 293 /// Uses |base_mip_level| as the mip level for output. 294 Result AddColorAttachment(Buffer* buf, 295 uint32_t location, 296 uint32_t base_mip_level); 297 /// Retrieves the location that |buf| is bound to in the pipeline. The 298 /// location will be written to |loc|. An error result will be return if 299 /// something goes wrong. 300 Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; 301 302 /// Returns a list of all resolve targets in this pipeline. GetResolveTargets()303 const std::vector<BufferInfo>& GetResolveTargets() const { 304 return resolve_targets_; 305 } 306 307 /// Adds |buf| as a multisample resolve target in the pipeline. 308 Result AddResolveTarget(Buffer* buf); 309 310 /// Sets |buf| as the depth/stencil buffer for this pipeline. 311 Result SetDepthStencilBuffer(Buffer* buf); 312 /// Returns information on the depth/stencil buffer bound to the pipeline. If 313 /// no depth buffer is bound the |BufferInfo::buffer| parameter will be 314 /// nullptr. GetDepthStencilBuffer()315 const BufferInfo& GetDepthStencilBuffer() const { 316 return depth_stencil_buffer_; 317 } 318 319 /// Returns pipeline data. GetPipelineData()320 PipelineData* GetPipelineData() { return &pipeline_data_; } 321 322 /// Returns information on all vertex buffers bound to the pipeline. GetVertexBuffers()323 const std::vector<BufferInfo>& GetVertexBuffers() const { 324 return vertex_buffers_; 325 } 326 /// Adds |buf| as a vertex buffer at |location| in the pipeline using |rate| 327 /// as the input rate, |format| as vertex data format, |offset| as a starting 328 /// offset for the vertex buffer data, and |stride| for the data stride in 329 /// bytes. 330 Result AddVertexBuffer(Buffer* buf, 331 uint32_t location, 332 InputRate rate, 333 Format* format, 334 uint32_t offset, 335 uint32_t stride); 336 337 /// Binds |buf| as the index buffer for this pipeline. 338 Result SetIndexBuffer(Buffer* buf); 339 /// Returns the index buffer bound to this pipeline or nullptr if no index 340 /// buffer bound. GetIndexBuffer()341 Buffer* GetIndexBuffer() const { return index_buffer_; } 342 343 /// Adds |buf| of |type| to the pipeline at the given |descriptor_set|, 344 /// |binding|, |base_mip_level|, |descriptor_offset|, |descriptor_range| and 345 /// |dynamic_offset|. 346 void AddBuffer(Buffer* buf, 347 BufferType type, 348 uint32_t descriptor_set, 349 uint32_t binding, 350 uint32_t base_mip_level, 351 uint32_t dynamic_offset, 352 uint64_t descriptor_offset, 353 uint64_t descriptor_range); 354 /// Adds |buf| to the pipeline at the given |arg_name|. 355 void AddBuffer(Buffer* buf, BufferType type, const std::string& arg_name); 356 /// Adds |buf| to the pipeline at the given |arg_no|. 357 void AddBuffer(Buffer* buf, BufferType type, uint32_t arg_no); 358 /// Returns information on all buffers in this pipeline. GetBuffers()359 const std::vector<BufferInfo>& GetBuffers() const { return buffers_; } 360 /// Clears all buffer bindings for given |descriptor_set| and |binding|. 361 void ClearBuffers(uint32_t descriptor_set, uint32_t binding); 362 363 /// Adds |sampler| to the pipeline at the given |descriptor_set| and 364 /// |binding|. 365 void AddSampler(Sampler* sampler, uint32_t descriptor_set, uint32_t binding); 366 /// Adds |sampler| to the pipeline at the given |arg_name|. 367 void AddSampler(Sampler* sampler, const std::string& arg_name); 368 /// Adds |sampler| to the pieline at the given |arg_no|. 369 void AddSampler(Sampler* sampler, uint32_t arg_no); 370 /// Adds an entry for an OpenCL literal sampler. 371 void AddSampler(uint32_t sampler_mask, 372 uint32_t descriptor_set, 373 uint32_t binding); 374 /// Clears all sampler bindings for given |descriptor_set| and |binding|. 375 void ClearSamplers(uint32_t descriptor_set, uint32_t binding); 376 377 /// Returns information on all samplers in this pipeline. GetSamplers()378 const std::vector<SamplerInfo>& GetSamplers() const { return samplers_; } 379 380 /// Updates the descriptor set and binding info for the OpenCL-C kernel bound 381 /// to the pipeline. No effect for other shader formats. 382 Result UpdateOpenCLBufferBindings(); 383 384 /// Returns the buffer which is currently bound to this pipeline at 385 /// |descriptor_set| and |binding|. 386 Buffer* GetBufferForBinding(uint32_t descriptor_set, uint32_t binding) const; 387 388 Result SetPushConstantBuffer(Buffer* buf); GetPushConstantBuffer()389 const BufferInfo& GetPushConstantBuffer() const { 390 return push_constant_buffer_; 391 } 392 393 /// Validates that the pipeline has been created correctly. 394 Result Validate() const; 395 396 /// Generates a default color attachment in B8G8R8A8_UNORM. 397 std::unique_ptr<Buffer> GenerateDefaultColorAttachmentBuffer(); 398 /// Generates a default depth/stencil attachment in D32_SFLOAT_S8_UINT format. 399 std::unique_ptr<Buffer> GenerateDefaultDepthStencilAttachmentBuffer(); 400 401 /// Information on values set for OpenCL-C plain-old-data args. 402 struct ArgSetInfo { 403 std::string name; 404 uint32_t ordinal = 0; 405 Format* fmt = nullptr; 406 Value value; 407 }; 408 409 /// Adds value from SET command. SetArg(ArgSetInfo && info)410 void SetArg(ArgSetInfo&& info) { set_arg_values_.push_back(std::move(info)); } SetArgValues()411 const std::vector<ArgSetInfo>& SetArgValues() const { 412 return set_arg_values_; 413 } 414 415 /// Generate the buffers necessary for OpenCL PoD arguments populated via SET 416 /// command. This should be called after all other buffers are bound. 417 Result GenerateOpenCLPodBuffers(); 418 419 /// Generate the samplers necessary for OpenCL literal samplers from the 420 /// descriptor map. This should be called after all other samplers are bound. 421 Result GenerateOpenCLLiteralSamplers(); 422 423 /// Generate the push constant buffers necessary for OpenCL kernels. 424 Result GenerateOpenCLPushConstants(); 425 426 private: 427 void UpdateFramebufferSizes(); 428 429 Result SetShaderRequiredSubgroupSize( 430 const Shader* shader, 431 const ShaderInfo::RequiredSubgroupSizeSetting setting, 432 const uint32_t subgroupSize); 433 434 Result CreatePushConstantBuffer(); 435 436 Result ValidateGraphics() const; 437 Result ValidateCompute() const; 438 439 PipelineType pipeline_type_ = PipelineType::kCompute; 440 std::string name_; 441 std::vector<ShaderInfo> shaders_; 442 std::vector<BufferInfo> color_attachments_; 443 std::vector<BufferInfo> resolve_targets_; 444 std::vector<BufferInfo> vertex_buffers_; 445 std::vector<BufferInfo> buffers_; 446 std::vector<std::unique_ptr<type::Type>> types_; 447 std::vector<SamplerInfo> samplers_; 448 std::vector<std::unique_ptr<Format>> formats_; 449 BufferInfo depth_stencil_buffer_; 450 BufferInfo push_constant_buffer_; 451 Buffer* index_buffer_ = nullptr; 452 PipelineData pipeline_data_; 453 uint32_t fb_width_ = 250; 454 uint32_t fb_height_ = 250; 455 456 std::vector<ArgSetInfo> set_arg_values_; 457 std::vector<std::unique_ptr<Buffer>> opencl_pod_buffers_; 458 /// Maps (descriptor set, binding) to the buffer for that binding pair. 459 std::map<std::pair<uint32_t, uint32_t>, Buffer*> opencl_pod_buffer_map_; 460 std::vector<std::unique_ptr<Sampler>> opencl_literal_samplers_; 461 std::unique_ptr<Buffer> opencl_push_constants_; 462 }; 463 464 } // namespace amber 465 466 #endif // SRC_PIPELINE_H_ 467