// Copyright 2018 The Amber Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef SRC_PIPELINE_H_ #define SRC_PIPELINE_H_ #include #include #include #include #include #include #include "amber/result.h" #include "src/buffer.h" #include "src/command_data.h" #include "src/sampler.h" #include "src/shader.h" namespace amber { enum class PipelineType { kCompute = 0, kGraphics }; /// Stores all information related to a pipeline. class Pipeline { public: /// Information on a shader attached to this pipeline. class ShaderInfo { public: ShaderInfo(Shader*, ShaderType type); ShaderInfo(const ShaderInfo&); ~ShaderInfo(); ShaderInfo& operator=(const ShaderInfo&) = default; // Set the optimization options for this shader. Optimizations are // specified like command-line arguments to spirv-opt (see its --help). // Parsing is done by spvtools::Optimizer::RegisterPassesFromFlags (see // SPIRV-Tools include/spirv-tools/optimizer.hpp). void SetShaderOptimizations(const std::vector& opts) { shader_optimizations_ = opts; } const std::vector& GetShaderOptimizations() const { return shader_optimizations_; } void SetCompileOptions(const std::vector& options) { compile_options_ = options; } const std::vector& GetCompileOptions() const { return compile_options_; } void SetShader(Shader* shader) { shader_ = shader; } const Shader* GetShader() const { return shader_; } void SetEntryPoint(const std::string& ep) { entry_point_ = ep; } const std::string& GetEntryPoint() const { return entry_point_; } void SetShaderType(ShaderType type) { shader_type_ = type; } ShaderType GetShaderType() const { return shader_type_; } const std::vector GetData() const { return data_; } void SetData(std::vector&& data) { data_ = std::move(data); } const std::map& GetSpecialization() const { return specialization_; } void AddSpecialization(uint32_t spec_id, uint32_t value) { specialization_[spec_id] = value; } /// Descriptor information for an OpenCL-C shader. struct DescriptorMapEntry { std::string arg_name = ""; enum class Kind : int { UNKNOWN, SSBO, UBO, POD, POD_UBO, RO_IMAGE, WO_IMAGE, SAMPLER, } kind; uint32_t descriptor_set = 0; uint32_t binding = 0; uint32_t arg_ordinal = 0; uint32_t pod_offset = 0; uint32_t pod_arg_size = 0; }; void AddDescriptorEntry(const std::string& kernel, DescriptorMapEntry&& entry) { descriptor_map_[kernel].emplace_back(std::move(entry)); } const std::unordered_map>& GetDescriptorMap() const { return descriptor_map_; } /// Push constant information for an OpenCL-C shader. struct PushConstant { enum class PushConstantType { kDimensions = 0, kGlobalOffset, }; PushConstantType type; uint32_t offset = 0; uint32_t size = 0; }; void AddPushConstant(PushConstant&& pc) { push_constants_.emplace_back(std::move(pc)); } const std::vector& GetPushConstants() const { return push_constants_; } private: Shader* shader_ = nullptr; ShaderType shader_type_; std::vector shader_optimizations_; std::string entry_point_; std::vector data_; std::map specialization_; std::unordered_map> descriptor_map_; std::vector push_constants_; std::vector compile_options_; }; /// Information on a buffer attached to the pipeline. /// /// The BufferInfo will have either (descriptor_set, binding) or location /// attached. struct BufferInfo { BufferInfo() = default; explicit BufferInfo(Buffer* buf) : buffer(buf) {} Buffer* buffer = nullptr; uint32_t descriptor_set = 0; uint32_t binding = 0; uint32_t location = 0; uint32_t base_mip_level = 0; std::string arg_name = ""; uint32_t arg_no = 0; BufferType type = BufferType::kUnknown; }; /// Information on a sampler attached to the pipeline. struct SamplerInfo { SamplerInfo() = default; explicit SamplerInfo(Sampler* samp) : sampler(samp) {} Sampler* sampler = nullptr; uint32_t descriptor_set = 0; uint32_t binding = 0; std::string arg_name = ""; uint32_t arg_no = 0; uint32_t mask = 0; }; static const char* kGeneratedColorBuffer; static const char* kGeneratedDepthBuffer; static const char* kGeneratedPushConstantBuffer; explicit Pipeline(PipelineType type); ~Pipeline(); std::unique_ptr Clone() const; bool IsGraphics() const { return pipeline_type_ == PipelineType::kGraphics; } bool IsCompute() const { return pipeline_type_ == PipelineType::kCompute; } PipelineType GetType() const { return pipeline_type_; } void SetName(const std::string& name) { name_ = name; } const std::string& GetName() const { return name_; } void SetFramebufferWidth(uint32_t fb_width) { fb_width_ = fb_width; UpdateFramebufferSizes(); } uint32_t GetFramebufferWidth() const { return fb_width_; } void SetFramebufferHeight(uint32_t fb_height) { fb_height_ = fb_height; UpdateFramebufferSizes(); } uint32_t GetFramebufferHeight() const { return fb_height_; } /// Adds |shader| of |type| to the pipeline. Result AddShader(Shader* shader, ShaderType type); /// Returns information on all bound shaders in this pipeline. std::vector& GetShaders() { return shaders_; } /// Returns information on all bound shaders in this pipeline. const std::vector& GetShaders() const { return shaders_; } /// Returns the ShaderInfo for |shader| or nullptr. const ShaderInfo* GetShader(Shader* shader) const { for (const auto& info : shaders_) { if (info.GetShader() == shader) return &info; } return nullptr; } /// Sets the |type| of |shader| in the pipeline. Result SetShaderType(const Shader* shader, ShaderType type); /// Sets the entry point |name| for |shader| in this pipeline. Result SetShaderEntryPoint(const Shader* shader, const std::string& name); /// Sets the optimizations (|opts|) for |shader| in this pipeline. Result SetShaderOptimizations(const Shader* shader, const std::vector& opts); /// Sets the compile options for |shader| in this pipeline. Result SetShaderCompileOptions(const Shader* shader, const std::vector& options); /// Returns a list of all colour attachments in this pipeline. const std::vector& GetColorAttachments() const { return color_attachments_; } /// Adds |buf| as a colour attachment at |location| in the pipeline. /// Uses |base_mip_level| as the mip level for output. Result AddColorAttachment(Buffer* buf, uint32_t location, uint32_t base_mip_level); /// Retrieves the location that |buf| is bound to in the pipeline. The /// location will be written to |loc|. An error result will be return if /// something goes wrong. Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; /// Sets |buf| as the depth buffer for this pipeline. Result SetDepthBuffer(Buffer* buf); /// Returns information on the depth buffer bound to the pipeline. If no /// depth buffer is bound the |BufferInfo::buffer| parameter will be nullptr. const BufferInfo& GetDepthBuffer() const { return depth_buffer_; } /// Returns information on all vertex buffers bound to the pipeline. const std::vector& GetVertexBuffers() const { return vertex_buffers_; } /// Adds |buf| as a vertex buffer at |location| in the pipeline. Result AddVertexBuffer(Buffer* buf, uint32_t location); /// Binds |buf| as the index buffer for this pipeline. Result SetIndexBuffer(Buffer* buf); /// Returns the index buffer bound to this pipeline or nullptr if no index /// buffer bound. Buffer* GetIndexBuffer() const { return index_buffer_; } /// Adds |buf| of |type| to the pipeline at the given |descriptor_set|, /// |binding| and |base_mip_level|. void AddBuffer(Buffer* buf, BufferType type, uint32_t descriptor_set, uint32_t binding, uint32_t base_mip_level); /// Adds |buf| to the pipeline at the given |arg_name|. void AddBuffer(Buffer* buf, BufferType type, const std::string& arg_name); /// Adds |buf| to the pipeline at the given |arg_no|. void AddBuffer(Buffer* buf, BufferType type, uint32_t arg_no); /// Returns information on all buffers in this pipeline. const std::vector& GetBuffers() const { return buffers_; } /// Adds |sampler| to the pipeline at the given |descriptor_set| and /// |binding|. void AddSampler(Sampler* sampler, uint32_t descriptor_set, uint32_t binding); /// Adds |sampler| to the pipeline at the given |arg_name|. void AddSampler(Sampler* sampler, const std::string& arg_name); /// Adds |sampler| to the pieline at the given |arg_no|. void AddSampler(Sampler* sampler, uint32_t arg_no); /// Adds an entry for an OpenCL literal sampler. void AddSampler(uint32_t sampler_mask, uint32_t descriptor_set, uint32_t binding); /// Returns information on all samplers in this pipeline. const std::vector& GetSamplers() const { return samplers_; } /// Updates the descriptor set and binding info for the OpenCL-C kernel bound /// to the pipeline. No effect for other shader formats. Result UpdateOpenCLBufferBindings(); /// Returns the buffer which is currently bound to this pipeline at /// |descriptor_set| and |binding|. Buffer* GetBufferForBinding(uint32_t descriptor_set, uint32_t binding) const; Result SetPushConstantBuffer(Buffer* buf); const BufferInfo& GetPushConstantBuffer() const { return push_constant_buffer_; } Result SetPolygonMode(PolygonMode mode); PolygonMode GetPolygonMode() const { return polygon_mode_; } /// Validates that the pipeline has been created correctly. Result Validate() const; /// Generates a default color attachment in B8G8R8A8_UNORM. std::unique_ptr GenerateDefaultColorAttachmentBuffer(); /// Generates a default depth attachment in D32_SFLOAT_S8_UINT format. std::unique_ptr GenerateDefaultDepthAttachmentBuffer(); /// Information on values set for OpenCL-C plain-old-data args. struct ArgSetInfo { std::string name; uint32_t ordinal = 0; Format* fmt = nullptr; Value value; }; /// Adds value from SET command. void SetArg(ArgSetInfo&& info) { set_arg_values_.push_back(std::move(info)); } const std::vector& SetArgValues() const { return set_arg_values_; } /// Generate the buffers necessary for OpenCL PoD arguments populated via SET /// command. This should be called after all other buffers are bound. Result GenerateOpenCLPodBuffers(); /// Generate the samplers necessary for OpenCL literal samplers from the /// descriptor map. This should be called after all other samplers are bound. Result GenerateOpenCLLiteralSamplers(); /// Generate the push constant buffers necessary for OpenCL kernels. Result GenerateOpenCLPushConstants(); private: void UpdateFramebufferSizes(); Result ValidateGraphics() const; Result ValidateCompute() const; PipelineType pipeline_type_ = PipelineType::kCompute; std::string name_; std::vector shaders_; std::vector color_attachments_; std::vector vertex_buffers_; std::vector buffers_; std::vector> types_; std::vector samplers_; std::vector> formats_; BufferInfo depth_buffer_; BufferInfo push_constant_buffer_; Buffer* index_buffer_ = nullptr; PolygonMode polygon_mode_ = PolygonMode::kFill; uint32_t fb_width_ = 250; uint32_t fb_height_ = 250; std::vector set_arg_values_; std::vector> opencl_pod_buffers_; /// Maps (descriptor set, binding) to the buffer for that binding pair. std::map, Buffer*> opencl_pod_buffer_map_; std::vector> opencl_literal_samplers_; std::unique_ptr opencl_push_constants_; }; } // namespace amber #endif // SRC_PIPELINE_H_