| /**************************************************************************** |
| ** |
| ** Copyright (C) 2008-2012 NVIDIA Corporation. |
| ** Copyright (C) 2019 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of Qt Quick 3D. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef QSSG_RENDER_SHADER_PROGRAM_H |
| #define QSSG_RENDER_SHADER_PROGRAM_H |
| |
| // |
| // W A R N I N G |
| // ------------- |
| // |
| // This file is not part of the Qt API. It exists purely as an |
| // implementation detail. This header file may change from version to |
| // version without notice, or even be removed. |
| // |
| // We mean it. |
| // |
| |
| #include <QtQuick3DRender/private/qssgrendershaderconstant_p.h> |
| |
| #include <QtCore/QString> |
| #include <QtCore/QHash> |
| |
| QT_BEGIN_NAMESPACE |
| |
| ///< forward declarations |
| class QSSGRenderContext; |
| class QSSGRenderVertexShader; |
| class QSSGRenderFragmentShader; |
| class QSSGRenderTessControlShader; |
| class QSSGRenderTessEvaluationShader; |
| class QSSGRenderGeometryShader; |
| class QSSGRenderShaderConstantBase; |
| class QSSGRenderShaderBufferBase; |
| class QSSGRenderComputeShader; |
| |
| typedef QHash<QByteArray, QSSGRef<QSSGRenderShaderConstantBase>> TShaderConstantMap; |
| typedef QHash<QByteArray, QSSGRef<QSSGRenderShaderBufferBase>> TShaderBufferMap; |
| |
| ///< A shader program is an object composed of a multiple shaders (vertex, fragment, |
| /// geometry,....) |
| class Q_QUICK3DRENDER_EXPORT QSSGRenderShaderProgram |
| { |
| Q_DISABLE_COPY(QSSGRenderShaderProgram) |
| public: |
| QAtomicInt ref; |
| |
| enum class ProgramType |
| { |
| Graphics, |
| Compute |
| }; |
| |
| private: |
| const QSSGRef<QSSGRenderContext> m_context; ///< pointer to context |
| const QSSGRef<QSSGRenderBackend> m_backend; ///< pointer to backend |
| const char *m_programName; /// Name of the program |
| QSSGRenderBackend::QSSGRenderBackendShaderProgramObject m_handle; ///< opaque backend handle |
| TShaderConstantMap m_constants; ///< map of shader constants |
| TShaderBufferMap m_shaderBuffers; ///< map of shader buffers |
| ProgramType m_programType; ///< shader type |
| QByteArray m_errorMessage; ///< contains the error message if linking fails |
| |
| template<typename TShaderObject> |
| void attach(TShaderObject *pShader); |
| template<typename TShaderObject> |
| void detach(TShaderObject *pShader); |
| |
| QSSGRenderShaderProgram(const QSSGRef<QSSGRenderContext> &context, const char *programName, bool separableProgram); |
| public: |
| ~QSSGRenderShaderProgram(); |
| |
| /** |
| * @brief link a program |
| * |
| * |
| * @return true if succesfuly linked. |
| */ |
| bool link(); |
| |
| ProgramType programType() const { return m_programType; } |
| |
| /** |
| * @brief Get Error Message |
| * |
| * |
| * @return error message. |
| */ |
| QByteArray errorMessage(); |
| |
| /** |
| * @brief Query constant class |
| * |
| * @param[in] constantName Pointer to constant name |
| * |
| * @return return a pointer to a constant class. |
| */ |
| QSSGRef<QSSGRenderShaderConstantBase> shaderConstant(const QByteArray &constantName) const; |
| |
| /** |
| * @brief Query a shader buffer (constant, ... ) |
| * |
| * @param[in] bufferName Pointer to constant name |
| * |
| * @return return a pointer to a constant class. |
| */ |
| QSSGRef<QSSGRenderShaderBufferBase> shaderBuffer(const QByteArray &bufferName) const; |
| |
| const QSSGRef<QSSGRenderBackend> &backend() const { return m_backend; } |
| |
| // concrete set functions |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, qint32 inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const qint32_2 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const qint32_3 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const qint32_4 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, bool inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const bool_2 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const bool_3 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const bool_4 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const float &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QVector2D &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QVector3D &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QVector4D &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QColor &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const quint32 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const quint32_2 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const quint32_3 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const quint32_4 &inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QMatrix3x3 &inValue, const qint32 inCount, bool inTranspose = false); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QMatrix4x4 &inValue, const qint32 inCount, bool inTranspose = false); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, const QSSGDataView<QMatrix4x4> inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderTexture2D *inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderTexture2D **inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderTextureCube *inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderTextureCube **inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderImage2D *inValue, const qint32 inCount); |
| void setConstantValue(QSSGRenderShaderConstantBase *inConstant, QSSGRenderDataBuffer *inValue, const qint32 inCount); |
| |
| /** |
| * @brief Template to set constant value via name |
| * |
| * @param[in] inConstantName Pointer to constant name |
| * @param[in] inValue Pointer to data |
| * @param[in] inCount Number of elements (array count) |
| * |
| * @return return a pointer to a constant class. |
| */ |
| template<typename TDataType> |
| void setPropertyValue(const char *inConstantName, const TDataType &inValue, const qint32 inCount = 1) |
| { |
| const QSSGRef<QSSGRenderShaderConstantBase> &theConstant = shaderConstant(inConstantName); |
| |
| if (theConstant) { |
| if (theConstant->getShaderConstantType() == QSSGDataTypeToShaderDataTypeMap<TDataType>::getType()) { |
| setConstantValue(theConstant.data(), inValue, inCount); |
| } else { |
| // Types don't match or property not found |
| Q_ASSERT(false); |
| } |
| } |
| } |
| |
| /** |
| * @brief Template to set constant value shader constant object |
| * |
| * @param[in] inConstant Pointer shader constant object |
| * @param[in] inValue Pointer to data |
| * @param[in] inCount Number of elements (array count) |
| * |
| * @return return a pointer to a constant class. |
| */ |
| template<typename TDataType> |
| void setPropertyValue(QSSGRenderShaderConstantBase *inConstant, const TDataType &inValue, const qint32 inCount = 1) |
| { |
| if (inConstant) { |
| if (inConstant->isCompatibleType(QSSGDataTypeToShaderDataTypeMap<TDataType>::getType())) { |
| setConstantValue(inConstant, inValue, inCount); |
| } else { |
| // Types don't match or property not found |
| Q_ASSERT(false); |
| } |
| } |
| } |
| |
| void bindComputeInput(QSSGRenderDataBuffer *inBuffer, quint32 inIndex); |
| |
| /** |
| * @brief get the backend object handle |
| * |
| * @return the backend object handle. |
| */ |
| QSSGRenderBackend::QSSGRenderBackendShaderProgramObject handle() const |
| { |
| return m_handle; |
| } |
| |
| /** |
| * @brief get the context object |
| * |
| * @return context which this shader belongs to. |
| */ |
| const QSSGRef<QSSGRenderContext> &renderContext(); |
| |
| /** |
| * @brief Create a shader program |
| * |
| * @param[in] context Pointer to context |
| * @param[in] programName Name of the program |
| * @param[in] vertShaderSource Vertex shader source code |
| * @param[in] fragShaderSource Fragment shader source code |
| * @param[in] tessControlShaderSource tessellation control shader source code |
| * @param[in] tessEvaluationShaderSource tessellation evaluation shader source code |
| * @param[in] separateProgram True if this will we a separate |
| * program |
| * @param[in] type Binary program type |
| * @param[in] binaryProgram True if program is binary |
| * |
| * @return a render result |
| */ |
| static QSSGRenderVertFragCompilationResult create( |
| const QSSGRef<QSSGRenderContext> &context, |
| const char *programName, |
| QSSGByteView vertShaderSource, |
| QSSGByteView fragShaderSource, |
| QSSGByteView tessControlShaderSource = QSSGByteView(), |
| QSSGByteView tessEvaluationShaderSource = QSSGByteView(), |
| QSSGByteView geometryShaderSource = QSSGByteView(), |
| bool separateProgram = false, |
| QSSGRenderShaderProgramBinaryType type = QSSGRenderShaderProgramBinaryType::Unknown, |
| bool binaryProgram = false); |
| |
| /** |
| * @brief Create a compute shader program |
| * |
| * @param[in] context Pointer to context |
| * @param[in] programName Name of the program |
| * @param[in] computeShaderSource Compute shader source code |
| * |
| * @return a render result |
| */ |
| static QSSGRenderVertFragCompilationResult createCompute(const QSSGRef<QSSGRenderContext> &context, |
| const char *programName, |
| QSSGByteView computeShaderSource); |
| }; |
| |
| // Helper class to cache the lookup of shader properties and apply them quickly in a typesafe |
| // way. |
| template<typename TDataType> |
| struct QSSGRenderCachedShaderProperty |
| { |
| QSSGRef<QSSGRenderShaderProgram> shader; ///< pointer to shader program |
| QSSGRef<QSSGRenderShaderConstantBase> constant; ///< poiner to shader constant object |
| |
| QSSGRenderCachedShaderProperty(const QByteArray &inConstantName, const QSSGRef<QSSGRenderShaderProgram> &inShader) |
| : shader(inShader) |
| { |
| const QSSGRef<QSSGRenderShaderConstantBase> &theConstant = inShader->shaderConstant(inConstantName); |
| if (theConstant) { |
| if (Q_LIKELY(theConstant->getShaderConstantType() == QSSGDataTypeToShaderDataTypeMap<TDataType>::getType())) { |
| constant = theConstant; |
| } else { |
| // Property types do not match, this probably indicates that the shader changed |
| // while the |
| // code creating this object did not change. |
| Q_ASSERT(false); |
| } |
| } |
| } |
| |
| QSSGRenderCachedShaderProperty() = default; |
| |
| void set(const TDataType &inValue) |
| { |
| // TODO: Make sure the raw pointer her is ok |
| if (constant) |
| shader->setPropertyValue(constant.data(), inValue); |
| } |
| |
| bool isValid() const { return constant != nullptr; } |
| }; |
| |
| template<typename TDataType, int size> |
| struct QSSGRenderCachedShaderPropertyArray |
| { |
| QSSGRef<QSSGRenderShaderProgram> shader; ///< pointer to shader program |
| QSSGRef<QSSGRenderShaderConstantBase> constant; ///< poiner to shader constant object |
| TDataType m_array[size]; |
| |
| QSSGRenderCachedShaderPropertyArray(const QByteArray &inConstantName, const QSSGRef<QSSGRenderShaderProgram> &inShader) |
| : shader(inShader) |
| { |
| memset(m_array, 0, sizeof(m_array)); |
| QSSGRef<QSSGRenderShaderConstantBase> theConstant = inShader->shaderConstant(inConstantName); |
| if (Q_LIKELY(theConstant)) { |
| if (theConstant->m_elementCount > 1 && theConstant->m_elementCount <= size |
| && theConstant->getShaderConstantType() == QSSGDataTypeToShaderDataTypeMap<TDataType *>::getType()) { |
| constant = theConstant; |
| } else { |
| // Property types do not match, this probably indicates that the shader changed |
| // while the code creating this object did not change. |
| Q_ASSERT(false); |
| } |
| } |
| } |
| |
| QSSGRenderCachedShaderPropertyArray() |
| { |
| memset(m_array, 0, sizeof(m_array)); |
| } |
| |
| void set(int count) |
| { |
| if (constant) |
| shader->setPropertyValue(constant.data(), static_cast<TDataType *>(m_array), qMin(size, count)); |
| } |
| |
| bool isValid() const { return constant != nullptr; } |
| }; |
| |
| // Helper class to cache the lookup of shader properties and apply them quickly in a typesafe |
| // way. |
| template<typename TDataType> |
| struct QSSGRenderCachedShaderBuffer |
| { |
| QSSGRef<QSSGRenderShaderProgram> shader; ///< pointer to shader program |
| QSSGRef<TDataType> shaderBuffer; ///< poiner to shader buffer object |
| |
| QSSGRenderCachedShaderBuffer(const QByteArray &inShaderBufferName, const QSSGRef<QSSGRenderShaderProgram> &inShader) |
| : shader(inShader) |
| { |
| TDataType *theShaderBuffer = static_cast<TDataType *>(inShader->shaderBuffer(inShaderBufferName).get()); |
| if (theShaderBuffer) |
| shaderBuffer = theShaderBuffer; |
| } |
| QSSGRenderCachedShaderBuffer() = default; |
| |
| void set() |
| { |
| if (shaderBuffer) { |
| shaderBuffer->validate(shader); |
| shaderBuffer->update(); |
| shaderBuffer->bindToProgram(shader); |
| } |
| } |
| |
| bool isValid() const { return shaderBuffer != 0; } |
| }; |
| |
| QT_END_NAMESPACE |
| |
| #endif |