summaryrefslogtreecommitdiffstats
path: root/src/render/materialsystem
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/materialsystem')
-rw-r--r--src/render/materialsystem/qeffect.cpp60
-rw-r--r--src/render/materialsystem/qmaterial.cpp102
-rw-r--r--src/render/materialsystem/qparameter.cpp127
-rw-r--r--src/render/materialsystem/qrenderpass.cpp91
-rw-r--r--src/render/materialsystem/qshaderdata_p.h7
-rw-r--r--src/render/materialsystem/qshaderprogram.cpp79
-rw-r--r--src/render/materialsystem/qshaderprogram.h15
-rw-r--r--src/render/materialsystem/qshaderprogram_p.h8
-rw-r--r--src/render/materialsystem/qtechnique.cpp128
-rw-r--r--src/render/materialsystem/shader.cpp63
-rw-r--r--src/render/materialsystem/shader_p.h18
-rw-r--r--src/render/materialsystem/shadercache.cpp5
-rw-r--r--src/render/materialsystem/shadercache_p.h1
13 files changed, 647 insertions, 57 deletions
diff --git a/src/render/materialsystem/qeffect.cpp b/src/render/materialsystem/qeffect.cpp
index 7778b5621..b611657c4 100644
--- a/src/render/materialsystem/qeffect.cpp
+++ b/src/render/materialsystem/qeffect.cpp
@@ -67,6 +67,35 @@ QEffectPrivate::QEffectPrivate()
The QEffect class combines a set of techniques and parameters used by those techniques to
produce a rendering effect for a material.
+ An QEffect instance should be shared among several QMaterial instances when possible.
+
+ \code
+ QEffect *effect = new QEffect();
+
+ // Create technique, render pass and shader
+ QTechnique *gl3Technique = new QTechnique();
+ QRenderPass *gl3Pass = new QRenderPass();
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ gl3Pass->setShaderProgram(glShader);
+
+ // Add the pass to the technique
+ gl3Technique->addRenderPass(gl3Pass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Add the technique to the effect
+ effect->addTechnique(gl3Technique);
+ \endcode
+
+ A QParameter defined on an Effect is overridden by a QParameter (of the same
+ name) defined in a QMaterial, QTechniqueFilter, QRenderPassFilter.
+
\sa QMaterial, QTechnique, QParameter
*/
@@ -81,6 +110,37 @@ QEffectPrivate::QEffectPrivate()
The Effect type combines a set of techniques and parameters used by those techniques to
produce a rendering effect for a material.
+ An Effect instance should be shared among several Material instances when possible.
+
+ A Parameter defined on an Effect is overridden by a QParameter (of the same
+ name) defined in a Material, TechniqueFilter, RenderPassFilter.
+
+ \code
+ Effect {
+ id: effect
+
+ technique: [
+ Technique {
+ id: gl3Technique
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: gl3Pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ ]
+ }
+ \endcode
+
\sa Material, Technique, Parameter
*/
diff --git a/src/render/materialsystem/qmaterial.cpp b/src/render/materialsystem/qmaterial.cpp
index ca0f86463..c6913441e 100644
--- a/src/render/materialsystem/qmaterial.cpp
+++ b/src/render/materialsystem/qmaterial.cpp
@@ -60,7 +60,58 @@
sound should reflect off an element, the temperature of a surface,
and so on.
- \sa Effect
+ In itself, a Material doesn't do anything. It's only when it references an
+ Effect node that a Material becomes useful.
+
+ In practice, it often happens that a single Effect is being referenced by
+ several Material components. This allows to only create the effect,
+ techniques, passes and shaders once while allowing to specify the material
+ by adding Parameter instances.
+
+ A Parameter defined on a Material is overridden by a Parameter (of the same
+ name) defined in a TechniqueFilter or a RenderPassFilter.
+
+ \code
+ Effect {
+ id: effect
+
+ technique: [
+ Technique {
+ id: gl3Technique
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: gl3Pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ ]
+ }
+
+ Material {
+ id: material1
+ parameters: [
+ Parameter { name: "color"; value: "green" }
+ ]
+ }
+
+ Material {
+ id: material2
+ parameters: [
+ Parameter { name: "color"; value: "white" }
+ ]
+ }
+ \endcode
+
+ \sa Effect, Technique, Parameter
*/
/*!
@@ -77,7 +128,54 @@
sound should reflect off an element, the temperature of a surface,
and so on.
- \sa QEffect
+ In itself, a QMaterial doesn't do anything. It's only when it references a
+ QEffect node that a QMaterial becomes useful.
+
+ In practice, it often happens that a single QEffect is being referenced by
+ several QMaterial components. This allows to only create the effect,
+ techniques, passes and shaders once while allowing to specify the material
+ by adding QParameter instances.
+
+ A QParameter defined on a QMaterial is overridden by a QParameter (of the same
+ name) defined in a QTechniqueFilter or a QRenderPassFilter.
+
+ \code
+ QMaterial *material1 = new QMaterial();
+ QMaterial *material2 = new QMaterial();
+
+ // Create effect, technique, render pass and shader
+ QEffect *effect = new QEffect();
+ QTechnique *gl3Technique = new QTechnique();
+ QRenderPass *gl3Pass = new QRenderPass();
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ gl3Pass->setShaderProgram(glShader);
+
+ // Add the pass to the technique
+ gl3Technique->addRenderPass(gl3Pass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Add the technique to the effect
+ effect->addTechnique(gl3Technique);
+
+ // Set the effect on the materials
+ material1->setEffect(effect);
+ material2->setEffect(effect);
+
+ // Set different parameters on the materials
+ const QString parameterName = QStringLiteral("color");
+ material1->addParameter(new QParameter(parameterName, QColor::fromRgbF(0.0f, 1.0f, 0.0f, 1.0f);
+ material2->addParameter(new QParameter(parameterName, QColor::fromRgbF(1.0f, 1.0f, 1.0f, 1.0f);
+
+ \endcode
+
+ \sa QEffect, QTechnique, QParameter
*/
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/qparameter.cpp b/src/render/materialsystem/qparameter.cpp
index 8f83fd02e..2ca7d176b 100644
--- a/src/render/materialsystem/qparameter.cpp
+++ b/src/render/materialsystem/qparameter.cpp
@@ -45,18 +45,127 @@
/*!
- * \qmltype Parameter
- * \instantiates Qt3DRender::QParameter
- * \inqmlmodule Qt3D.Render
- * \brief Provides storage for a name and value pair.
+ \qmltype Parameter
+ \instantiates Qt3DRender::QParameter
+ \inqmlmodule Qt3D.Render
+ \brief Provides storage for a name and value pair. This maps to a shader uniform.
+
+ A Parameter can be referenced by a RenderPass, Technique, Effect, Material,
+ TechniqueFilter, RenderPassFilter. At runtime, depending on which shader is
+ selected for a given step of the rendering, the value contained in a
+ Parameter will be converted and uploaded if the shader contains a uniform
+ with a name matching that of the Parameter.
+
+ \code
+ Parameter {
+ name: "diffuseColor"
+ value: "blue"
+ }
+
+ // Works with the following GLSL uniform shader declarations
+ // uniform vec4 diffuseColor;
+ // uniform vec3 diffuseColor;
+ // uniform vec2 diffuseColor;
+ // uniform float diffuseColor;
+ \endcode
+
+ \note some care must be taken to ensure the value wrapped by a Parameter
+ can actually be converted to what the real uniform expect. Giving a value
+ stored as an int where the actual shader uniform is of type float could
+ result in undefined behaviors.
+
+ \note when the targeted uniform is an array, the name should be the name
+ of the uniform with [0] appended to it.
+
+ \code
+ Parameter {
+ name: "diffuseValues[0]"
+ value: [0.0, 1.0. 2.0, 3.0, 4.0, 883.0, 1340.0, 1584.0]
+ }
+
+ // Matching GLSL shader uniform declaration
+ // uniform float diffuseValues[8];
+ \endcode
+
+ When it comes to texture support, the Parameter value should be set to the
+ appropriate Texture subclass that matches the sampler type of the shader
+ uniform.
+
+ \code
+ Parameter {
+ name: "diffuseTexture"
+ value: Texture2D { ... }
+ }
+
+ // Works with the following GLSL uniform shader declaration
+ // uniform sampler2D diffuseTexture
+ \endcode
+
+ \sa Texture
*/
/*!
- * \class Qt3DRender::QParameter
- * \inheaderfile Qt3DRender/QParameter
- * \inmodule Qt3DRender
- *
- * \brief Provides storage for a name and value pair.
+ \class Qt3DRender::QParameter
+ \inheaderfile Qt3DRender/QParameter
+ \inmodule Qt3DRender
+ \brief Provides storage for a name and value pair. This maps to a shader uniform.
+
+ A QParameter can be referenced by a QRenderPass, QTechnique, QEffect, QMaterial,
+ QTechniqueFilter, QRenderPassFilter. At runtime, depending on which shader is
+ selected for a given step of the rendering, the value contained in a
+ QParameter will be converted and uploaded if the shader contains a uniform
+ with a name matching that of the QParameter.
+
+ \code
+ QParameter *param = new QParameter();
+ param->setName(QStringLiteral("diffuseColor"));
+ param->setValue(QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Alternatively you can create and set a QParameter this way
+ QParameter *param2 = new QParameter(QStringLiteral("diffuseColor"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Such QParameters will work with the following GLSL uniform shader declarations
+ // uniform vec4 diffuseColor;
+ // uniform vec3 diffuseColor;
+ // uniform vec2 diffuseColor;
+ // uniform float diffuseColor;
+ \endcode
+
+ \note some care must be taken to ensure the value wrapped by a QParameter
+ can actually be converted to what the real uniform expect. Giving a value
+ stored as an int where the actual shader uniform is of type float could
+ result in undefined behaviors.
+
+ \note when the targeted uniform is an array, the name should be the name
+ of the uniform with [0] appended to it.
+
+ \code
+ QParameter *param = new QParameter();
+ QVariantList values = QVariantList() << 0.0f << 1.0f << 2.0f << 3.0f << 4.0f << 883.0f << 1340.0f << 1584.0f;
+
+ param->setName(QStringLiteral("diffuseValues[0]"));
+ param->setValue(values);
+
+ // Matching GLSL shader uniform declaration
+ // uniform float diffuseValues[8];
+ \endcode
+
+ When it comes to texture support, the QParameter value should be set to the
+ appropriate QAbstractTexture subclass that matches the sampler type of the shader
+ uniform.
+
+ \code
+ QTexture2D *texture = new QTexture2D();
+ ...
+ QParameter *param = new QParameter();
+ param->setName(QStringLiteral("diffuseTexture"));
+ param->setValue(QVariant::fromValue(texture));
+
+ // Works with the following GLSL uniform shader declaration
+ // uniform sampler2D diffuseTexture
+ \endcode
+
+ \sa QAbstractTexture
*/
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/qrenderpass.cpp b/src/render/materialsystem/qrenderpass.cpp
index dd6363816..61f844be3 100644
--- a/src/render/materialsystem/qrenderpass.cpp
+++ b/src/render/materialsystem/qrenderpass.cpp
@@ -72,9 +72,40 @@ QRenderPassPrivate::QRenderPassPrivate()
a list of FilterKey objects, a list of RenderState objects and a list
of \l Parameter objects.
- RenderPass executes the ShaderProgram using the given render states and parameters
- when its filter keys match the filter keys in RenderPassFilter or when no filter
- keys are specified and no RenderPassFilter is present in the FrameGraph.
+ RenderPass executes the ShaderProgram using the given RenderState and
+ Parameter nodes when at least one of FilterKey nodes being referenced
+ matches any of the FilterKey nodes in RenderPassFilter or when no FilterKey
+ nodes are specified and no RenderPassFilter is present in the FrameGraph.
+
+ If the RenderPass defines a Parameter, it will be overridden by a Parameter
+ with the same name if it exists in any of the Technique, Effect, Material,
+ TechniqueFilter, RenderPassFilter associated with the pass at runtime. This
+ still can be useful to define sane default values.
+
+ At render time, for each leaf node of the FrameGraph a base render state is
+ recorded by accumulating states defined by all RenderStateSet nodes in the
+ FrameGraph branch. Each RenderPass can overload this base render state by
+ specifying its own RenderState nodes.
+
+ \code
+ RenderPass {
+ id: pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ parameters: [
+ Parameters { name: "color"; value: "red" }
+ ]
+ filterKeys: [
+ FilterKey { name: "name"; value: "zFillPass" }
+ ]
+ renderStates: [
+ DepthTest { }
+ ]
+ }
+ \endcode
+
+ \sa RenderPassFilter, FilterKey, Parameter, RenderState, Effect, Technique
*/
/*!
@@ -88,10 +119,54 @@ QRenderPassPrivate::QRenderPassPrivate()
of a Qt3DRender::QShaderProgram and a list of Qt3DRender::QFilterKey objects,
a list of Qt3DRender::QRenderState objects and a list of Qt3DRender::QParameter objects.
- QRenderPass executes the QShaderProgram using the given render states and parameters
- when its filter keys match the filter keys in Qt3DRender::QRenderPassFilter or
- when no filter keys are specified and no QRenderPassFilter is present
- in the FrameGraph.
+ QRenderPass executes the QShaderProgram using the given QRenderState and
+ QParameter nodes when at least one of QFilterKey nodes being referenced
+ matches any of the QFilterKey nodes in QRenderPassFilter or when no
+ QFilterKey nodes are specified and no QRenderPassFilter is present in the
+ FrameGraph.
+
+ If the QRenderPass defines a QParameter, it will be overridden by a
+ QParameter with the same name if it exists in any of the QTechnique,
+ QEffect, QMaterial, QTechniqueFilter, QRenderPassFilter associated with the
+ pass at runtime. This still can be useful to define sane default values.
+
+ At render time, for each leaf node of the FrameGraph a base render state is
+ recorded by accumulating states defined by all QRenderStateSet nodes in the
+ FrameGraph branch. Each QRenderPass can overload this base render state by
+ specifying its own QRenderState nodes.
+
+ \code
+ // Create the render passes
+ QRenderPass *pass = new QRenderPass();
+
+ // Create shader program
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ pass->setShaderProgram(glShader);
+
+ // Create a FilterKey
+ QFilterKey *filterKey = new QFilterKey();
+ filterKey->setName(QStringLiteral("name"));
+ fitlerKey->setValue(QStringLiteral("zFillPass"));
+
+ // Add the FilterKey to the pass
+ pass->addFilterKey(filterKey);
+
+ // Create a QParameter
+ QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Add parameter to pass
+ pass->addParameter(colorParameter);
+
+ // Create a QRenderState
+ QDepthTest *depthTest = new QDepthTest();
+
+ // Add the render state to the pass
+ pass->addRenderState(depthTest);
+ \endcode
+
+ \sa QRenderPassFilter, QFilterKey, QParameter, QRenderState, QEffect, QTechnique
*/
/*!
\typedef ParameterList
@@ -236,7 +311,7 @@ QVector<QFilterKey *> QRenderPass::filterKeys() const
/*!
Adds a render \a state to the rendering pass. That implies that
when the pass is executed at render time, the globally set render state will
- be modifed by the states defined locally by the Qt3DRender::QRenderPass.
+ be modified by the states defined locally by the Qt3DRender::QRenderPass.
\note not defining any Qt3DRender::QRenderState in a pass will result in the pass using
the globally set render state for a given FrameGraph branch execution path.
diff --git a/src/render/materialsystem/qshaderdata_p.h b/src/render/materialsystem/qshaderdata_p.h
index bfa139890..17faee9ed 100644
--- a/src/render/materialsystem/qshaderdata_p.h
+++ b/src/render/materialsystem/qshaderdata_p.h
@@ -62,7 +62,6 @@ namespace Qt3DRender {
namespace {
const int qVectorShaderDataTypeId = qMetaTypeId<QVector<QShaderData*> >();
-const int qShaderDataTypeId = qMetaTypeId<QShaderData*>();
}
@@ -70,10 +69,10 @@ class QShaderDataPropertyReader: public PropertyReaderInterface
{
QVariant readProperty(const QVariant &v) Q_DECL_OVERRIDE
{
- QShaderData *shaderData = nullptr;
+ const auto node = v.value<Qt3DCore::QNode *>();
- if (v.userType() == qShaderDataTypeId && (shaderData = v.value<QShaderData *>()) != nullptr) {
- return QVariant::fromValue(shaderData->id());
+ if (node) {
+ return QVariant::fromValue(node->id());
} else if (v.userType() == qVectorShaderDataTypeId) {
QVariantList vlist;
const auto data_ = v.value<QVector<QShaderData *> >();
diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp
index 522f021aa..2a65d257c 100644
--- a/src/render/materialsystem/qshaderprogram.cpp
+++ b/src/render/materialsystem/qshaderprogram.cpp
@@ -80,15 +80,48 @@
\value Compute Compute shader
*/
+/*!
+ \enum QShaderProgram::ShaderStatus
+
+ This enum identifies the status of shader used.
+
+ \value NotReady The shader hasn't been compiled and linked yet
+ \value Ready The shader was successfully compiled
+ \value Error An error occurred while compiling the shader
+*/
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
QShaderProgramPrivate::QShaderProgramPrivate()
: QNodePrivate()
+ , m_status(QShaderProgram::NotReady)
{
}
+void QShaderProgramPrivate::setLog(const QString &log)
+{
+ Q_Q(QShaderProgram);
+ if (log != m_log) {
+ m_log = log;
+ const bool blocked = q->blockNotifications(true);
+ emit q->logChanged(m_log);
+ q->blockNotifications(blocked);
+ }
+}
+
+void QShaderProgramPrivate::setStatus(QShaderProgram::Status status)
+{
+ Q_Q(QShaderProgram);
+ if (status != m_status) {
+ m_status = status;
+ const bool blocked = q->blockNotifications(true);
+ emit q->statusChanged(m_status);
+ q->blockNotifications(blocked);
+ }
+}
+
QShaderProgram::QShaderProgram(QNode *parent)
: QNode(*new QShaderProgramPrivate, parent)
{
@@ -104,6 +137,18 @@ QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent)
{
}
+void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Q_D(QShaderProgram);
+ if (change->type() == Qt3DCore::PropertyUpdated) {
+ const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->propertyName() == QByteArrayLiteral("log"))
+ d->setLog(e->value().toString());
+ else if (e->propertyName() == QByteArrayLiteral("status"))
+ d->setStatus(static_cast<QShaderProgram::Status>(e->value().toInt()));
+ }
+}
+
/*!
\qmlproperty string ShaderProgram::vertexShaderCode
@@ -308,6 +353,40 @@ QByteArray QShaderProgram::shaderCode(ShaderType type) const
}
}
+/*!
+ \qmlproperty string ShaderProgram::log
+
+ Holds the log of the current shader program. This is useful to diagnose a
+ compilation failure of the shader program.
+*/
+/*!
+ \property QShaderProgram::log
+
+ Holds the log of the current shader program. This is useful to diagnose a
+ compilation failure of the shader program.
+*/
+QString QShaderProgram::log() const
+{
+ Q_D(const QShaderProgram);
+ return d->m_log;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::status
+
+ Holds the status of the current shader program.
+*/
+/*!
+ \property QShaderProgram::status
+
+ Holds the status of the current shader program.
+*/
+QShaderProgram::Status QShaderProgram::status() const
+{
+ Q_D(const QShaderProgram);
+ return d->m_status;
+}
+
static QByteArray deincludify(const QString &filePath)
{
QFile f(filePath);
diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h
index 442a25b2e..8c3da1a4a 100644
--- a/src/render/materialsystem/qshaderprogram.h
+++ b/src/render/materialsystem/qshaderprogram.h
@@ -58,6 +58,8 @@ class QT3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode
Q_PROPERTY(QByteArray geometryShaderCode READ geometryShaderCode WRITE setGeometryShaderCode NOTIFY geometryShaderCodeChanged)
Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode WRITE setFragmentShaderCode NOTIFY fragmentShaderCodeChanged)
Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode WRITE setComputeShaderCode NOTIFY computeShaderCodeChanged)
+ Q_PROPERTY(QString log READ log NOTIFY logChanged REVISION 9)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged REVISION 9)
public:
explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr);
@@ -73,6 +75,13 @@ public:
};
Q_ENUM(ShaderType) // LCOV_EXCL_LINE
+ enum Status {
+ NotReady = 0,
+ Ready,
+ Error
+ };
+ Q_ENUM(Status) // LCOV_EXCL_LINE
+
// Source code in-line
QByteArray vertexShaderCode() const;
QByteArray tessellationControlShaderCode() const;
@@ -84,6 +93,9 @@ public:
void setShaderCode(ShaderType type, const QByteArray &shaderCode);
QByteArray shaderCode(ShaderType type) const;
+ QString log() const;
+ Status status() const;
+
Q_INVOKABLE static QByteArray loadSource(const QUrl &sourceUrl);
public Q_SLOTS:
@@ -101,9 +113,12 @@ Q_SIGNALS:
void geometryShaderCodeChanged(const QByteArray &geometryShaderCode);
void fragmentShaderCodeChanged(const QByteArray &fragmentShaderCode);
void computeShaderCodeChanged(const QByteArray &computeShaderCode);
+ void logChanged(const QString &log);
+ void statusChanged(Status status);
protected:
explicit QShaderProgram(QShaderProgramPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(QShaderProgram)
diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h
index 5f695a279..6bdde68f1 100644
--- a/src/render/materialsystem/qshaderprogram_p.h
+++ b/src/render/materialsystem/qshaderprogram_p.h
@@ -52,13 +52,12 @@
//
#include <private/qnode_p.h>
+#include <Qt3DRender/qshaderprogram.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QShaderProgram;
-
class QShaderProgramPrivate : public Qt3DCore::QNodePrivate
{
public:
@@ -77,6 +76,11 @@ public:
QByteArray m_geometryShaderCode;
QByteArray m_fragmentShaderCode;
QByteArray m_computeShaderCode;
+ QString m_log;
+ QShaderProgram::Status m_status;
+
+ void setLog(const QString &log);
+ void setStatus(QShaderProgram::Status status);
};
struct QShaderProgramData
diff --git a/src/render/materialsystem/qtechnique.cpp b/src/render/materialsystem/qtechnique.cpp
index 74505bfbd..df142cdee 100644
--- a/src/render/materialsystem/qtechnique.cpp
+++ b/src/render/materialsystem/qtechnique.cpp
@@ -68,14 +68,61 @@ QTechniquePrivate::~QTechniquePrivate()
\since 5.7
\brief Encapsulates a Technique.
- A Technique specifies a set of RenderPass objects, FilterKey objects, Parameter objects
- and a GraphicsApiFilter, which together define a rendering technique the given
- graphics API can render. The filter keys are used by TechniqueFilter
- to select specific techinques at specific parts of the FrameGraph.
- If the same parameter is specified both in Technique and RenderPass, the one
- in Technique overrides the one used in the RenderPass.
-
- \sa Qt3D.Render::Effect
+ A Technique specifies a set of RenderPass objects, FilterKey objects,
+ Parameter objects and a GraphicsApiFilter, which together define a
+ rendering technique the given graphics API can render. The filter keys are
+ used by TechniqueFilter to select specific techniques at specific parts of
+ the FrameGraph. If two Parameter instances with the same name are specified
+ in a Technique and a RenderPass, the one in Technique overrides the one
+ used in the RenderPass.
+
+ When creating an Effect that targets several versions of a graphics API, it
+ is useful to create several Technique nodes each with a graphicsApiFilter
+ set to match one of the targeted versions. At runtime, the Qt3D renderer
+ will select the most appropriate Technique based on which graphics API
+ versions are supported and (if specified) the FilterKey nodes that satisfy
+ a given TechniqueFilter in the FrameGraph.
+
+ \note When using OpenGL as the graphics API for rendering, Qt3D relies on
+ the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
+ to decide what is the most appropriate GL version available. If you need to
+ customize the QSurfaceFormat, do not forget to apply it with
+ QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
+ will likely have no effect on Qt3D related rendering.
+
+ \code
+ Technique {
+ id: gl3Technique
+ parameters: [
+ Parameter { name: "color"; value: "orange" }
+ ]
+ filterKeys: [
+ FilterKey { name: "name"; value: "zFillTechnique" }
+ ]
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: firstPass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ },
+ RenderPass {
+ id: secondPass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ \endcode
+
+ \sa Effect, RenderPass, TechniqueFilter
*/
/*!
@@ -85,15 +132,62 @@ QTechniquePrivate::~QTechniquePrivate()
\since 5.7
\brief Encapsulates a Technique.
- A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass objects,
- Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
- a Qt3DRender::QGraphicsApiFilter, which together define a rendering technique the given
- graphics API can render. The filter keys are used by Qt3DRender::QTechniqueFilter
- to select specific techinques at specific parts of the FrameGraph.
- If the same parameter is specified both in QTechnique and QRenderPass, the one
- in QTechnique overrides the one used in the QRenderPass.
-
- \sa Qt3DRender::QEffect
+ A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass
+ objects, Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
+ a Qt3DRender::QGraphicsApiFilter, which together define a rendering
+ technique the given graphics API can render. The filter keys are used by
+ Qt3DRender::QTechniqueFilter to select specific techniques at specific
+ parts of the FrameGraph. If two QParameter instances with the same name are
+ specified in a QTechnique and a QRenderPass, the one in Technique overrides
+ the one used in the QRenderPass.
+
+ When creating an QEffect that targets several versions of a graphics API,
+ it is useful to create several QTechnique nodes each with a
+ graphicsApiFilter set to match one of the targeted GL versions. At runtime,
+ the Qt3D renderer will select the most appropriate QTechnique based on
+ which graphics API versions are supported and (if specified) the QFilterKey
+ nodes that satisfy a given QTechniqueFilter in the FrameGraph.
+
+ \note When using OpenGL as the graphics API for rendering, Qt3D relies on
+ the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
+ to decide what is the most appropriate GL version available. If you need to
+ customize the QSurfaceFormat, do not forget to apply it with
+ QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
+ will likely have no effect on Qt3D related rendering.
+
+ \code
+ QTechnique *gl3Technique = new QTechnique();
+
+ // Create the render passes
+ QRenderPass *firstPass = new QRenderPass();
+ QRenderPass *secondPass = new QRenderPass();
+
+ // Add the passes to the technique
+ gl3Technique->addRenderPass(firstPass);
+ gl3Technique->addRenderPass(secondPass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Create a FilterKey
+ QFilterKey *filterKey = new QFilterKey();
+ filterKey->setName(QStringLiteral("name"));
+ fitlerKey->setValue(QStringLiteral("zFillPass"));
+
+ // Add the FilterKey to the Technique
+ gl3Technique->addFilterKey(filterKey);
+
+ // Create a QParameter
+ QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Add parameter to technique
+ gl3Technique->addParameter(colorParameter);
+ \endcode
+
+ \sa QEffect, QRenderPass, QTechniqueFilter
*/
/*!
diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp
index bd0af0bed..915ca1d54 100644
--- a/src/render/materialsystem/shader.cpp
+++ b/src/render/materialsystem/shader.cpp
@@ -59,10 +59,11 @@ namespace Qt3DRender {
namespace Render {
Shader::Shader()
- : BackendNode()
+ : BackendNode(ReadWrite)
, m_isLoaded(false)
, m_dna(0)
, m_graphicsContext(nullptr)
+ , m_status(QShaderProgram::NotReady)
{
m_shaderCode.resize(static_cast<int>(QShaderProgram::Compute) + 1);
}
@@ -71,8 +72,8 @@ Shader::~Shader()
{
// TO DO: ShaderProgram is leaked as of now
// Fix that taking care that they may be shared given a same dna
-
- QObject::disconnect(m_contextConnection);
+ if (m_graphicsContext)
+ QObject::disconnect(m_contextConnection);
}
void Shader::cleanup()
@@ -84,6 +85,7 @@ void Shader::cleanup()
if (m_graphicsContext)
m_graphicsContext->removeShaderProgramReference(this);
m_graphicsContext = nullptr;
+ QObject::disconnect(m_contextConnection);
}
QBackendNode::setEnabled(false);
@@ -96,6 +98,7 @@ void Shader::cleanup()
m_uniforms.clear();
m_attributes.clear();
m_uniformBlocks.clear();
+ m_status = QShaderProgram::NotReady;
}
void Shader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -183,8 +186,10 @@ void Shader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_shaderCode[QShaderProgram::Compute] = propertyValue.toByteArray();
m_isLoaded = false;
}
- if (!m_isLoaded)
+ if (!m_isLoaded) {
+ setStatus(QShaderProgram::NotReady);
updateDNA();
+ }
markDirty(AbstractRenderer::AllDirty);
}
@@ -253,6 +258,14 @@ ShaderStorageBlock Shader::storageBlockForBlockName(const QString &blockName)
return ShaderStorageBlock();
}
+// To be called from a worker thread
+void Shader::submitPendingNotifications()
+{
+ const QVector<Qt3DCore::QPropertyUpdatedChangePtr> notifications = std::move(m_pendingNotifications);
+ for (const Qt3DCore::QPropertyUpdatedChangePtr &notification : notifications)
+ notifyObservers(notification);
+}
+
void Shader::prepareUniforms(ShaderParameterPack &pack)
{
const PackUniformHash &values = pack.uniforms();
@@ -261,7 +274,7 @@ void Shader::prepareUniforms(ShaderParameterPack &pack)
const auto end = values.cend();
while (it != end) {
// Find if there's a uniform with the same name id
- for (const ShaderUniform &uniform : m_uniforms) {
+ for (const ShaderUniform &uniform : qAsConst(m_uniforms)) {
if (uniform.m_nameId == it.key()) {
pack.setSubmissionUniform(uniform);
break;
@@ -298,8 +311,8 @@ void Shader::updateDNA()
QMutexLocker locker(&m_mutex);
uint attachmentHash = 0;
- QHash<QString, int>::const_iterator it = m_fragOutputs.begin();
- QHash<QString, int>::const_iterator end = m_fragOutputs.end();
+ QHash<QString, int>::const_iterator it = m_fragOutputs.cbegin();
+ QHash<QString, int>::const_iterator end = m_fragOutputs.cend();
while (it != end) {
attachmentHash += ::qHash(it.value()) + ::qHash(it.key());
++it;
@@ -360,11 +373,11 @@ void Shader::initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformB
qCDebug(Shaders) << "Initializing Uniform Block {" << m_uniformBlockNames[i] << "}";
// Find all active uniforms for the shader block
- QVector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.begin();
- const QVector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.end();
+ QVector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.cbegin();
+ const QVector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.cend();
- QVector<QString>::const_iterator uniformNamesIt = m_uniformsNames.begin();
- const QVector<QString>::const_iterator uniformNamesEnd = m_attributesNames.end();
+ QVector<QString>::const_iterator uniformNamesIt = m_uniformsNames.cbegin();
+ const QVector<QString>::const_iterator uniformNamesEnd = m_attributesNames.cend();
QHash<QString, ShaderUniform> activeUniformsInBlock;
@@ -402,7 +415,7 @@ void Shader::initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &sh
Initializes this Shader's state relating to attributes, global block uniforms and
and named uniform blocks by copying these details from \a other.
*/
-void Shader::initialize(const Shader &other)
+void Shader::initializeFromReference(const Shader &other)
{
Q_ASSERT(m_dna == other.m_dna);
m_uniformsNamesIds = other.m_uniformsNamesIds;
@@ -420,6 +433,32 @@ void Shader::initialize(const Shader &other)
m_shaderStorageBlockNames = other.m_shaderStorageBlockNames;
m_shaderStorageBlocks = other.m_shaderStorageBlocks;
m_isLoaded = other.m_isLoaded;
+ setStatus(other.status());
+ setLog(other.log());
+}
+
+void Shader::setLog(const QString &log)
+{
+ if (log != m_log) {
+ m_log = log;
+ Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("log");
+ e->setValue(QVariant::fromValue(m_log));
+ m_pendingNotifications.push_back(e);
+ }
+}
+
+void Shader::setStatus(QShaderProgram::Status status)
+{
+ if (status != m_status) {
+ m_status = status;
+ Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("status");
+ e->setValue(QVariant::fromValue(m_status));
+ m_pendingNotifications.push_back(e);
+ }
}
} // namespace Render
diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h
index ad68a3bd6..b5127f5ec 100644
--- a/src/render/materialsystem/shader_p.h
+++ b/src/render/materialsystem/shader_p.h
@@ -54,6 +54,8 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/shaderparameterpack_p.h>
#include <Qt3DRender/private/shadervariables_p.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
#include <QMutex>
#include <QVector>
@@ -63,8 +65,6 @@ class QOpenGLShaderProgram;
namespace Qt3DRender {
-class QShaderProgram;
-
namespace Render {
class ShaderManager;
@@ -118,6 +118,12 @@ public:
ShaderStorageBlock storageBlockForBlockNameId(int blockNameId);
ShaderStorageBlock storageBlockForBlockName(const QString &blockName);
+ inline QString log() const { return m_log; }
+ inline QShaderProgram::Status status() const { return m_status; }
+
+ void submitPendingNotifications();
+ inline bool hasPendingNotifications() const { return !m_pendingNotifications.empty(); }
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -148,6 +154,10 @@ private:
mutable QMutex m_mutex;
GraphicsContext *m_graphicsContext;
QMetaObject::Connection m_contextConnection;
+ QString m_log;
+ QShaderProgram::Status m_status;
+
+ QVector<Qt3DCore::QPropertyUpdatedChangePtr> m_pendingNotifications;
void updateDNA();
@@ -157,7 +167,9 @@ private:
void initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformBlockDescription);
void initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &shaderStorageBlockDescription);
- void initialize(const Shader &other);
+ void initializeFromReference(const Shader &other);
+ void setLog(const QString &log);
+ void setStatus(QShaderProgram::Status status);
friend class GraphicsContext;
};
diff --git a/src/render/materialsystem/shadercache.cpp b/src/render/materialsystem/shadercache.cpp
index de3842386..4ddf26799 100644
--- a/src/render/materialsystem/shadercache.cpp
+++ b/src/render/materialsystem/shadercache.cpp
@@ -151,6 +151,11 @@ QOpenGLShaderProgram *ShaderCache::getShaderProgramForDNA(ProgramDNA dna) const
return m_programHash.value(dna, nullptr);
}
+QVector<Qt3DCore::QNodeId> ShaderCache::shaderIdsForProgram(ProgramDNA dna) const
+{
+ return m_programRefs.value(dna);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/materialsystem/shadercache_p.h b/src/render/materialsystem/shadercache_p.h
index 3cbc6bd0c..24a55876e 100644
--- a/src/render/materialsystem/shadercache_p.h
+++ b/src/render/materialsystem/shadercache_p.h
@@ -79,6 +79,7 @@ public:
// Only ever used from the OpenGL submission thread
QOpenGLShaderProgram *getShaderProgramForDNA(ProgramDNA dna) const;
+ QVector<Qt3DCore::QNodeId> shaderIdsForProgram(ProgramDNA dna) const;
private:
// Only ever used from the OpenGL submission thread