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