blob: 704016cf0dd7811563f764d60b3b285c34af8506 [file] [log] [blame]
/****************************************************************************
**
** 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