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_SCRIPT_H_
16 #define SRC_SCRIPT_H_
17 
18 #include <algorithm>
19 #include <cstdint>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "amber/recipe.h"
27 #include "amber/result.h"
28 #include "src/buffer.h"
29 #include "src/command.h"
30 #include "src/engine.h"
31 #include "src/format.h"
32 #include "src/pipeline.h"
33 #include "src/sampler.h"
34 #include "src/shader.h"
35 #include "src/virtual_file_store.h"
36 
37 namespace amber {
38 
39 /// Class representing the script to be run against an engine.
40 class Script : public RecipeImpl {
41  public:
42   Script();
43   ~Script() override;
44 
45   bool IsKnownFeature(const std::string& name) const;
46 
47   /// Retrieves information on the shaders in the given script.
48   std::vector<ShaderInfo> GetShaderInfo() const override;
49 
50   /// Returns required features in the given recipe.
GetRequiredFeatures()51   std::vector<std::string> GetRequiredFeatures() const override {
52     return engine_info_.required_features;
53   }
54 
55   /// Returns required device extensions in the given recipe.
GetRequiredDeviceExtensions()56   std::vector<std::string> GetRequiredDeviceExtensions() const override {
57     return engine_info_.required_device_extensions;
58   }
59 
60   /// Returns required instance extensions in the given recipe.
GetRequiredInstanceExtensions()61   std::vector<std::string> GetRequiredInstanceExtensions() const override {
62     return engine_info_.required_instance_extensions;
63   }
64 
65   /// Sets the fence timeout to |timeout_ms|.
SetFenceTimeout(uint32_t timeout_ms)66   void SetFenceTimeout(uint32_t timeout_ms) override {
67     engine_data_.fence_timeout_ms = timeout_ms;
68   }
69 
70   /// Sets or clears runtime layer bit to |enabled|.
SetPipelineRuntimeLayerEnabled(bool enabled)71   void SetPipelineRuntimeLayerEnabled(bool enabled) override {
72     engine_data_.pipeline_runtime_layer_enabled = enabled;
73   }
74 
75   /// Adds |pipeline| to the list of known pipelines. The |pipeline| must have
76   /// a unique name over all pipelines in the script.
AddPipeline(std::unique_ptr<Pipeline> pipeline)77   Result AddPipeline(std::unique_ptr<Pipeline> pipeline) {
78     if (name_to_pipeline_.count(pipeline->GetName()) > 0)
79       return Result("duplicate pipeline name provided");
80 
81     pipelines_.push_back(std::move(pipeline));
82     name_to_pipeline_[pipelines_.back()->GetName()] = pipelines_.back().get();
83     return {};
84   }
85 
86   /// Retrieves the pipeline with |name|, |nullptr| if not found.
GetPipeline(const std::string & name)87   Pipeline* GetPipeline(const std::string& name) const {
88     auto it = name_to_pipeline_.find(name);
89     return it == name_to_pipeline_.end() ? nullptr : it->second;
90   }
91 
92   /// Retrieves a list of all pipelines.
GetPipelines()93   const std::vector<std::unique_ptr<Pipeline>>& GetPipelines() const {
94     return pipelines_;
95   }
96 
97   /// Adds |shader| to the list of known shaders. The |shader| must have a
98   /// unique name over all shaders in the script.
AddShader(std::unique_ptr<Shader> shader)99   Result AddShader(std::unique_ptr<Shader> shader) {
100     if (name_to_shader_.count(shader->GetName()) > 0)
101       return Result("duplicate shader name provided");
102 
103     shaders_.push_back(std::move(shader));
104     name_to_shader_[shaders_.back()->GetName()] = shaders_.back().get();
105     return {};
106   }
107 
108   /// Retrieves the shader with |name|, |nullptr| if not found.
GetShader(const std::string & name)109   Shader* GetShader(const std::string& name) const {
110     auto it = name_to_shader_.find(name);
111     return it == name_to_shader_.end() ? nullptr : it->second;
112   }
113 
114   /// Retrieves a list of all shaders.
GetShaders()115   const std::vector<std::unique_ptr<Shader>>& GetShaders() const {
116     return shaders_;
117   }
118 
119   /// Adds |buffer| to the list of known buffers. The |buffer| must have a
120   /// unique name over all buffers in the script.
AddBuffer(std::unique_ptr<Buffer> buffer)121   Result AddBuffer(std::unique_ptr<Buffer> buffer) {
122     if (name_to_buffer_.count(buffer->GetName()) > 0)
123       return Result("duplicate buffer name provided");
124 
125     buffers_.push_back(std::move(buffer));
126     name_to_buffer_[buffers_.back()->GetName()] = buffers_.back().get();
127     return {};
128   }
129 
130   /// Retrieves the buffer with |name|, |nullptr| if not found.
GetBuffer(const std::string & name)131   Buffer* GetBuffer(const std::string& name) const {
132     auto it = name_to_buffer_.find(name);
133     return it == name_to_buffer_.end() ? nullptr : it->second;
134   }
135 
136   /// Retrieves a list of all buffers.
GetBuffers()137   const std::vector<std::unique_ptr<Buffer>>& GetBuffers() const {
138     return buffers_;
139   }
140 
141   /// Adds |sampler| to the list of known sampler. The |sampler| must have a
142   /// unique name over all samplers in the script.
AddSampler(std::unique_ptr<Sampler> sampler)143   Result AddSampler(std::unique_ptr<Sampler> sampler) {
144     if (name_to_sampler_.count(sampler->GetName()) > 0)
145       return Result("duplicate sampler name provided");
146 
147     samplers_.push_back(std::move(sampler));
148     name_to_sampler_[samplers_.back()->GetName()] = samplers_.back().get();
149     return {};
150   }
151 
152   /// Retrieves the sampler with |name|, |nullptr| if not found.
GetSampler(const std::string & name)153   Sampler* GetSampler(const std::string& name) const {
154     auto it = name_to_sampler_.find(name);
155     return it == name_to_sampler_.end() ? nullptr : it->second;
156   }
157 
158   /// Retrieves a list of all samplers.
GetSamplers()159   const std::vector<std::unique_ptr<Sampler>>& GetSamplers() const {
160     return samplers_;
161   }
162 
163   /// Adds |feature| to the list of features that must be supported by the
164   /// engine.
AddRequiredFeature(const std::string & feature)165   void AddRequiredFeature(const std::string& feature) {
166     engine_info_.required_features.push_back(feature);
167   }
168 
169   /// Checks if |feature| is in required features
IsRequiredFeature(const std::string & feature)170   bool IsRequiredFeature(const std::string& feature) const {
171     return std::find(engine_info_.required_features.begin(),
172                      engine_info_.required_features.end(),
173                      feature) != engine_info_.required_features.end();
174   }
175 
176   /// Adds |ext| to the list of device extensions that must be supported.
AddRequiredDeviceExtension(const std::string & ext)177   void AddRequiredDeviceExtension(const std::string& ext) {
178     engine_info_.required_device_extensions.push_back(ext);
179   }
180 
181   /// Adds |ext| to the list of instance extensions that must be supported.
AddRequiredInstanceExtension(const std::string & ext)182   void AddRequiredInstanceExtension(const std::string& ext) {
183     engine_info_.required_instance_extensions.push_back(ext);
184   }
185 
186   /// Adds |ext| to the list of extensions that must be supported by the engine.
187   /// Note, this should only be used by the VkScript engine where there is no
188   /// differentiation between the types of extensions.
189   void AddRequiredExtension(const std::string& ext);
190 
191   /// Retrieves the engine configuration data for this script.
GetEngineData()192   EngineData& GetEngineData() { return engine_data_; }
193   /// Retrieves the engine configuration data for this script.
GetEngineData()194   const EngineData& GetEngineData() const { return engine_data_; }
195 
196   /// Sets |cmds| to the list of commands to execute against the engine.
SetCommands(std::vector<std::unique_ptr<Command>> cmds)197   void SetCommands(std::vector<std::unique_ptr<Command>> cmds) {
198     commands_ = std::move(cmds);
199   }
200 
201   /// Retrieves the list of commands to execute against the engine.
GetCommands()202   const std::vector<std::unique_ptr<Command>>& GetCommands() const {
203     return commands_;
204   }
205 
206   /// Sets the SPIR-V target environment.
SetSpvTargetEnv(const std::string & env)207   void SetSpvTargetEnv(const std::string& env) { spv_env_ = env; }
208   /// Retrieves the SPIR-V target environment.
GetSpvTargetEnv()209   const std::string& GetSpvTargetEnv() const { return spv_env_; }
210 
211   /// Assign ownership of the format to the script.
RegisterFormat(std::unique_ptr<Format> fmt)212   Format* RegisterFormat(std::unique_ptr<Format> fmt) {
213     formats_.push_back(std::move(fmt));
214     return formats_.back().get();
215   }
216 
217   /// Assigns ownership of the type to the script.
RegisterType(std::unique_ptr<type::Type> type)218   type::Type* RegisterType(std::unique_ptr<type::Type> type) {
219     types_.push_back(std::move(type));
220     return types_.back().get();
221   }
222 
223   /// Adds |type| to the list of known types. The |type| must have
224   /// a unique name over all types in the script.
AddType(const std::string & name,std::unique_ptr<type::Type> type)225   Result AddType(const std::string& name, std::unique_ptr<type::Type> type) {
226     if (name_to_type_.count(name) > 0)
227       return Result("duplicate type name provided");
228 
229     name_to_type_[name] = std::move(type);
230     return {};
231   }
232 
233   /// Retrieves the type with |name|, |nullptr| if not found.
GetType(const std::string & name)234   type::Type* GetType(const std::string& name) const {
235     auto it = name_to_type_.find(name);
236     return it == name_to_type_.end() ? nullptr : it->second.get();
237   }
238 
239   // Returns the virtual file store.
GetVirtualFiles()240   VirtualFileStore* GetVirtualFiles() const { return virtual_files_.get(); }
241 
242   /// Adds the virtual file with content |content| to the virtual file path
243   /// |path|. If there's already a virtual file with the given path, an error is
244   /// returned.
AddVirtualFile(const std::string & path,const std::string & content)245   Result AddVirtualFile(const std::string& path, const std::string& content) {
246     return virtual_files_->Add(path, content);
247   }
248 
249   /// Look up the virtual file by path. If the file was found, the content is
250   /// assigned to content.
GetVirtualFile(const std::string & path,std::string * content)251   Result GetVirtualFile(const std::string& path, std::string* content) const {
252     return virtual_files_->Get(path, content);
253   }
254 
255   type::Type* ParseType(const std::string& str);
256 
257  private:
258   struct {
259     std::vector<std::string> required_features;
260     std::vector<std::string> required_device_extensions;
261     std::vector<std::string> required_instance_extensions;
262   } engine_info_;
263 
264   EngineData engine_data_;
265   std::string spv_env_;
266   std::map<std::string, Shader*> name_to_shader_;
267   std::map<std::string, Buffer*> name_to_buffer_;
268   std::map<std::string, Sampler*> name_to_sampler_;
269   std::map<std::string, Pipeline*> name_to_pipeline_;
270   std::map<std::string, std::unique_ptr<type::Type>> name_to_type_;
271   std::vector<std::unique_ptr<Shader>> shaders_;
272   std::vector<std::unique_ptr<Command>> commands_;
273   std::vector<std::unique_ptr<Buffer>> buffers_;
274   std::vector<std::unique_ptr<Sampler>> samplers_;
275   std::vector<std::unique_ptr<Pipeline>> pipelines_;
276   std::vector<std::unique_ptr<type::Type>> types_;
277   std::vector<std::unique_ptr<Format>> formats_;
278   std::unique_ptr<VirtualFileStore> virtual_files_;
279 };
280 
281 }  // namespace amber
282 
283 #endif  // SRC_SCRIPT_H_
284