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_VULKAN_PIPELINE_H_
16 #define SRC_VULKAN_PIPELINE_H_
17 
18 #include <memory>
19 #include <string>
20 #include <unordered_map>
21 #include <vector>
22 
23 #include "amber/result.h"
24 #include "amber/vulkan_header.h"
25 #include "src/cast_hash.h"
26 #include "src/engine.h"
27 #include "src/vulkan/buffer_backed_descriptor.h"
28 #include "src/vulkan/command_buffer.h"
29 #include "src/vulkan/push_constant.h"
30 #include "src/vulkan/resource.h"
31 
32 namespace amber {
33 
34 class BufferCommand;
35 
36 namespace vulkan {
37 
38 class ComputePipeline;
39 class Device;
40 class GraphicsPipeline;
41 
42 /// Base class for a pipeline in Vulkan.
43 class Pipeline {
44  public:
45   virtual ~Pipeline();
46 
IsGraphics()47   bool IsGraphics() const { return pipeline_type_ == PipelineType::kGraphics; }
IsCompute()48   bool IsCompute() const { return pipeline_type_ == PipelineType::kCompute; }
49 
50   GraphicsPipeline* AsGraphics();
51   ComputePipeline* AsCompute();
52 
53   Result AddBufferDescriptor(const BufferCommand*);
54   Result AddSamplerDescriptor(const SamplerCommand*);
55 
56   /// Add |buffer| data to the push constants at |offset|.
57   Result AddPushConstantBuffer(const Buffer* buf, uint32_t offset);
58 
59   /// Reads back the contents of resources of all descriptors to a
60   /// buffer data object and put it into buffer data queue in host.
61   Result ReadbackDescriptorsToHostDataQueue();
62 
63   std::unordered_map<Buffer*, std::unique_ptr<Resource>>&
GetDescriptorTransferResources()64   GetDescriptorTransferResources() {
65     return descriptor_transfer_resources_;
66   }
67 
SetEntryPointName(VkShaderStageFlagBits stage,const std::string & entry)68   void SetEntryPointName(VkShaderStageFlagBits stage,
69                          const std::string& entry) {
70     entry_points_[stage] = entry;
71   }
72 
GetCommandBuffer()73   CommandBuffer* GetCommandBuffer() const { return command_.get(); }
GetDevice()74   Device* GetDevice() const { return device_; }
75 
76  protected:
77   Pipeline(
78       PipelineType type,
79       Device* device,
80       uint32_t fence_timeout_ms,
81       bool    pipeline_runtime_layer_enabled,
82       const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info);
83 
84   /// Initializes the pipeline.
85   Result Initialize(CommandPool* pool);
86 
87   Result GetDescriptorSlot(uint32_t desc_set,
88                            uint32_t binding,
89                            Descriptor** desc);
90   void UpdateDescriptorSetsIfNeeded();
91 
92   Result SendDescriptorDataToDeviceIfNeeded();
93   void BindVkDescriptorSets(const VkPipelineLayout& pipeline_layout);
94 
95   /// Records a Vulkan command for push contant.
96   Result RecordPushConstant(const VkPipelineLayout& pipeline_layout);
97 
GetVkShaderStageInfo()98   const std::vector<VkPipelineShaderStageCreateInfo>& GetVkShaderStageInfo()
99       const {
100     return shader_stage_info_;
101   }
102 
103   const char* GetEntryPointName(VkShaderStageFlagBits stage) const;
GetFenceTimeout()104   uint32_t GetFenceTimeout() const { return fence_timeout_ms_; }
GetPipelineRuntimeLayerEnabled()105   bool     GetPipelineRuntimeLayerEnabled()
106        const { return pipeline_runtime_layer_enabled_; }
107 
108   Result CreateVkPipelineLayout(VkPipelineLayout* pipeline_layout);
109 
110   Device* device_ = nullptr;
111   std::unique_ptr<CommandBuffer> command_;
112 
113  private:
114   struct DescriptorSetInfo {
115     bool empty = true;
116     VkDescriptorSetLayout layout = VK_NULL_HANDLE;
117     VkDescriptorPool pool = VK_NULL_HANDLE;
118     VkDescriptorSet vk_desc_set = VK_NULL_HANDLE;
119     std::vector<std::unique_ptr<Descriptor>> descriptors;
120   };
121 
122   /// Creates Vulkan descriptor related objects.
123   Result CreateVkDescriptorRelatedObjectsIfNeeded();
124   Result CreateDescriptorSetLayouts();
125   Result CreateDescriptorPools();
126   Result CreateDescriptorSets();
127   /// Adds a buffer used by a descriptor. The added buffers are be stored in
128   /// |descriptor_buffers_| vector in the order they are added.
129   Result AddDescriptorBuffer(Buffer* amber_buffer);
130 
131   PipelineType pipeline_type_;
132   std::vector<DescriptorSetInfo> descriptor_set_info_;
133   std::vector<VkPipelineShaderStageCreateInfo> shader_stage_info_;
134   std::unordered_map<Buffer*, std::unique_ptr<Resource>>
135       descriptor_transfer_resources_;
136   /// Buffers used by descriptors (buffer descriptors and image descriptors).
137   std::vector<Buffer*> descriptor_buffers_;
138 
139   uint32_t fence_timeout_ms_ = 1000;
140   bool pipeline_runtime_layer_enabled_ = false;
141   bool descriptor_related_objects_already_created_ = false;
142   std::unordered_map<VkShaderStageFlagBits,
143                      std::string,
144                      CastHash<VkShaderStageFlagBits>>
145       entry_points_;
146 
147   std::unique_ptr<PushConstant> push_constant_;
148 };
149 
150 }  // namespace vulkan
151 }  // namespace amber
152 
153 #endif  // SRC_VULKAN_PIPELINE_H_
154