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