// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #ifndef MATERIALX_MSLPROGRAM_H #define MATERIALX_MSLPROGRAM_H /// @file /// MSL Program interfaces #include #include #include #include #include #include #import MATERIALX_NAMESPACE_BEGIN // Shared pointer to a MslProgram using MslProgramPtr = std::shared_ptr; using MetalFramebufferPtr = std::shared_ptr; /// @class MslProgram /// A class representing an executable MSL program. /// /// There are two main interfaces which can be used. One which takes in a HwShader and one which /// allows for explicit setting of shader stage code. class MX_RENDERMSL_API MslProgram { public: /// Create a MSL program instance static MslProgramPtr create() { return MslProgramPtr(new MslProgram()); } /// Destructor virtual ~MslProgram(); /// @name Shader code setup /// @{ /// Set up code stages to validate based on an input hardware shader. /// @param shader Hardware shader to use void setStages(ShaderPtr shader); /// Set the code stages based on a list of stage strings. /// Refer to the ordering of stages as defined by a HwShader. /// @param stage Name of the shader stage. /// @param sourceCode Source code of the shader stage. void addStage(const string& stage, const string& sourceCode); /// Get source code string for a given stage. /// @return Shader stage string. String is empty if not found. const string& getStageSourceCode(const string& stage) const; /// Clear out any existing stages void clearStages(); /// Return the shader, if any, used to generate this program. ShaderPtr getShader() const { return _shader; } /// @} /// @name Program validation and introspection /// @{ /// Create the pipeline state object from stages specified /// @param device MetalDevice that pipeline state object is being created on. /// @param framebuffer specifies information about output frame buffer. /// An exception is thrown if the program cannot be created. /// The exception will contain a list of program creation errors. /// @return Pipeline State Object identifier. id build(id device, MetalFramebufferPtr frameBuffer); /// Structure to hold information about program inputs. /// The structure is populated by directly scanning the program so may not contain /// some inputs listed on any associated HwShader as those inputs may have been /// optimized out if they are unused. struct MX_RENDERMSL_API Input { static MTLDataType INVALID_METAL_TYPE; /// Program location. -1 means an invalid location int location; /// Metal type of the input. MTLDataType resourceType; /// Size. int size; /// Input type string. Will only be non-empty if initialized stages with a HwShader string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) string path; /// Unit string unit; /// Colorspace string colorspace; /// Program input constructor Input(int inputLocation, MTLDataType inputType, int inputSize, const string& inputPath) : location(inputLocation), resourceType(inputType), size(inputSize), isConstant(false), path(inputPath) { } }; /// Program input structure shared pointer type using InputPtr = std::shared_ptr; /// Program input shaded pointer map type using InputMap = std::unordered_map; /// Get list of program input uniforms. /// The program must have been created successfully first. /// An exception is thrown if the parsing of the program for uniforms cannot be performed. /// @return Program uniforms list. const InputMap& getUniformsList(); /// Get list of program input attributes. /// The program must have been created successfully first. /// An exception is thrown if the parsing of the program for attribute cannot be performed. /// @return Program attributes list. const InputMap& getAttributesList(); /// Find the locations in the program which starts with a given variable name /// @param variable Variable to search for /// @param variableList List of program inputs to search /// @param foundList Returned list of found program inputs. Empty if none found. /// @param exactMatch Search for exact variable name match. void findInputs(const string& variable, const InputMap& variableList, InputMap& foundList, bool exactMatch); /// @} /// @name Program activation /// @{ /// Bind the pipeline state object to the command encoder. /// @param renderCmdEncoder encoder that binds the pipeline state object. /// @return False if failed bool bind(id renderCmdEncoder); /// Bind inputs /// @param renderCmdEncoder encoder that inputs will be bound to. /// @param cam Camera object use to view the object /// @param geometryHandler /// @param imageHandler /// @param lightHandler /// @return void - No return value void prepareUsedResources(id renderCmdEncoder, CameraPtr cam, GeometryHandlerPtr geometryHandler, ImageHandlerPtr imageHandler, LightHandlerPtr lightHandler); /// Return true if a uniform with the given name is present. bool hasUniform(const string& name); /// Bind a value to the uniform with the given name. void bindUniform(const string& name, ConstValuePtr value, bool errorIfMissing = true); /// Bind attribute buffers to attribute inputs. /// A hardware buffer of the given attribute type is created and bound to the program locations /// for the input attribute. /// @param renderCmdEncoder Metal Render Command Encoder that the attribute being bind to /// @param inputs Attribute inputs to bind to /// @param mesh Mesh containing streams to bind void bindAttribute(id renderCmdEncoder, const MslProgram::InputMap& inputs, MeshPtr mesh); /// Bind input geometry partition (indexing) void bindPartition(MeshPartitionPtr partition); /// Bind input geometry streams void bindMesh(id renderCmdEncoder, MeshPtr mesh); /// Queries the index buffer assigned to a mesh partition id getIndexBuffer(MeshPartitionPtr mesh) { if (_indexBufferIds.find(mesh) != _indexBufferIds.end()) return _indexBufferIds[mesh]; return nil; } /// Unbind any bound geometry void unbindGeometry(); /// Bind any input textures void bindTextures(id renderCmdEncoder, LightHandlerPtr lightHandler, ImageHandlerPtr imageHandler); void bindTexture(ImageHandlerPtr imageHandler, string shaderTextureName, ImagePtr imagePtr, ImageSamplingProperties samplingProperties); /// Bind lighting void bindLighting(LightHandlerPtr lightHandler, ImageHandlerPtr imageHandler); /// Bind view information void bindViewInformation(CameraPtr camera); /// Bind time and frame void bindTimeAndFrame(float time = 1.0f, float frame = 1.0f); /// @} /// @name Utilities /// @{ /// Returns if alpha blending is enabled. bool isTransparent() const { return _alphaBlendingEnabled; } /// Specify textures bound to this program shouldn't be mip mapped. void setEnableMipMaps(bool enableMipMapping) { _enableMipMapping = enableMipMapping; } /// Print all uniforms to the given stream. void printUniforms(std::ostream& outputStream); /// Print all attributes to the given stream. void printAttributes(std::ostream& outputStream); /// @} public: static unsigned int UNDEFINED_METAL_RESOURCE_ID; static int UNDEFINED_METAL_PROGRAM_LOCATION; protected: MslProgram(); // Update a list of program input uniforms const InputMap& updateUniformsList(); // Update a list of program input attributes const InputMap& updateAttributesList(); // Clear out any cached input lists void clearInputLists(); // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, unsigned int uniformLocation, const FilePath& filePath, ImageSamplingProperties samplingProperties, ImageHandlerPtr imageHandler); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, unsigned int uniformLocation, ImagePtr imagePtr, ImageHandlerPtr imageHandler); void bindUniformBuffers(id renderCmdEncoder, LightHandlerPtr lightHandler, CameraPtr camera); // Delete any currently created pso void reset(); // Utility to map a MaterialX type to an METAL type static MTLDataType mapTypeToMetalType(TypeDesc type); private: // Stages used to create program // Map of stage name and its source code StringMap _stages; // Generated pipeline state object. A non-zero number indicates a valid shader program. id _pso = nil; MTLRenderPipelineReflection* _psoReflection = nil; // List of program input uniforms InputMap _uniformList; std::unordered_map _globalUniformNameList; // List of program input attributes InputMap _attributeList; std::unordered_map _explicitBoundImages; // Hardware shader (if any) used for program creation ShaderPtr _shader; // Attribute buffer resource handles // for each attribute identifier in the program std::unordered_map> _attributeBufferIds; // Attribute indexing buffer handle std::map> _indexBufferIds; // Program texture map std::unordered_map _programTextures; // Metal Device Object id _device = nil; // Currently bound mesh MeshPtr _boundMesh = nullptr; bool _alphaBlendingEnabled = false; float _time = 0.0f; float _frame = 0.0f; bool _enableMipMapping = true; }; MATERIALX_NAMESPACE_END #endif