diff options
-rw-r--r-- | src/render/materialsystem/qshaderprogram.cpp | 42 | ||||
-rw-r--r-- | src/render/materialsystem/qshaderprogram.h | 11 | ||||
-rw-r--r-- | src/render/materialsystem/qshaderprogram_p.h | 2 | ||||
-rw-r--r-- | src/render/materialsystem/shader.cpp | 13 | ||||
-rw-r--r-- | src/render/materialsystem/shader_p.h | 4 | ||||
-rw-r--r-- | tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp | 65 | ||||
-rw-r--r-- | tests/auto/render/shader/tst_shader.cpp | 48 |
7 files changed, 182 insertions, 3 deletions
diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp index c4e14ea2c..6f59e6be0 100644 --- a/src/render/materialsystem/qshaderprogram.cpp +++ b/src/render/materialsystem/qshaderprogram.cpp @@ -332,6 +332,15 @@ \value Error An error occurred while compiling the shader */ +/*! + \enum QShaderProgram::Format + + This enum identifies the format of the shader code used. + + \value GLSL OpenGL + \value SPIRV Vulkan, OpenGL 5 +*/ + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -339,6 +348,7 @@ namespace Qt3DRender { QShaderProgramPrivate::QShaderProgramPrivate() : QNodePrivate() , m_status(QShaderProgram::NotReady) + , m_format(QShaderProgram::GLSL) { } @@ -617,7 +627,7 @@ QString QShaderProgram::log() const } /*! - \qmlproperty string ShaderProgram::status + \qmlproperty enumeration ShaderProgram::status Holds the status of the current shader program. */ @@ -635,6 +645,35 @@ QShaderProgram::Status QShaderProgram::status() const return d->m_status; } +void QShaderProgram::setFormat(QShaderProgram::Format format) +{ + Q_D(QShaderProgram); + if (format != d->m_format) { + d->m_format = format; + emit formatChanged(format); + } +} + +/*! + \qmlproperty enumeration ShaderProgram::format + \since 6.0 + + Holds the format of the code provided on the ShaderProgram. + The default is ShaderProgram.GLSL +*/ +/*! + \property QShaderProgram::format + \since 6.0 + + Holds the format of the code provided on the ShaderProgram. + The default is ShaderProgram.GLSL +*/ +QShaderProgram::Format QShaderProgram::format() const +{ + Q_D(const QShaderProgram); + return d->m_format; +} + QByteArray QShaderProgramPrivate::deincludify(const QString &filePath) { QFile f(filePath); @@ -699,6 +738,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgram::createNodeCreationChange() c data.geometryShaderCode = d->m_geometryShaderCode; data.fragmentShaderCode = d->m_fragmentShaderCode; data.computeShaderCode = d->m_computeShaderCode; + data.format = d->m_format; return creationChange; } diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h index 49c1076e5..ba51cec2f 100644 --- a/src/render/materialsystem/qshaderprogram.h +++ b/src/render/materialsystem/qshaderprogram.h @@ -60,6 +60,7 @@ class Q_3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode 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) + Q_PROPERTY(Format format READ format WRITE setFormat NOTIFY formatChanged) public: explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr); @@ -82,6 +83,12 @@ public: }; Q_ENUM(Status) // LCOV_EXCL_LINE + enum Format { + GLSL = 0, + SPIRV + }; + Q_ENUM(Format) // LCOV_EXCL_LINE + // Source code in-line QByteArray vertexShaderCode() const; QByteArray tessellationControlShaderCode() const; @@ -96,6 +103,9 @@ public: QString log() const; Status status() const; + void setFormat(Format format); + Format format() const; + Q_INVOKABLE static QByteArray loadSource(const QUrl &sourceUrl); public Q_SLOTS: @@ -115,6 +125,7 @@ Q_SIGNALS: void computeShaderCodeChanged(const QByteArray &computeShaderCode); void logChanged(const QString &log); void statusChanged(Status status); + void formatChanged(Format format); protected: explicit QShaderProgram(QShaderProgramPrivate &dd, Qt3DCore::QNode *parent = nullptr); diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h index 20883f03a..8a14255a8 100644 --- a/src/render/materialsystem/qshaderprogram_p.h +++ b/src/render/materialsystem/qshaderprogram_p.h @@ -73,6 +73,7 @@ public: QByteArray m_computeShaderCode; QString m_log; QShaderProgram::Status m_status; + QShaderProgram::Format m_format; void setLog(const QString &log); void setStatus(QShaderProgram::Status status); @@ -89,6 +90,7 @@ struct QShaderProgramData QByteArray geometryShaderCode; QByteArray fragmentShaderCode; QByteArray computeShaderCode; + QShaderProgram::Format format; }; } // namespace Qt3DRender diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index afa70ed41..f3570f78d 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -85,6 +85,7 @@ Shader::Shader() : BackendNode(ReadWrite) , m_requiresFrontendSync(false) , m_status(QShaderProgram::NotReady) + , m_format(QShaderProgram::GLSL) , m_dirty(false) { m_shaderCode.resize(static_cast<int>(QShaderProgram::Compute) + 1); @@ -98,6 +99,7 @@ void Shader::cleanup() { QBackendNode::setEnabled(false); m_status = QShaderProgram::NotReady; + m_format = QShaderProgram::GLSL; m_log.clear(); m_dirty = false; } @@ -120,6 +122,7 @@ void Shader::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) if (code != m_shaderCode.value(shaderType)) setShaderCode(shaderType, code); } + setFormat(node->format()); } void Shader::setShaderCode(QShaderProgram::ShaderType type, const QByteArray &code) @@ -134,6 +137,16 @@ void Shader::setShaderCode(QShaderProgram::ShaderType type, const QByteArray &co markDirty(AbstractRenderer::ShadersDirty); } +void Shader::setFormat(QShaderProgram::Format format) +{ + if (format == m_format) + return; + m_format = format; + m_dirty = true; + setStatus(QShaderProgram::NotReady); + markDirty(AbstractRenderer::ShadersDirty); +} + QVector<QByteArray> Shader::shaderCode() const { return m_shaderCode; diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index 6f5383e88..9065a6524 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -106,6 +106,9 @@ public: inline QString log() const { return m_log; } inline QShaderProgram::Status status() const { return m_status; } + + void setFormat(QShaderProgram::Format format); + QShaderProgram::Format format() const { return m_format; } bool isDirty() const { return m_dirty; } void unsetDirty() { m_dirty = false; } @@ -118,6 +121,7 @@ private: QString m_log; QShaderProgram::Status m_status; bool m_requiresFrontendSync; + QShaderProgram::Format m_format; bool m_dirty; QVector<Qt3DCore::QPropertyUpdatedChangePtr> m_pendingNotifications; diff --git a/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp index a261d0860..7b96847a3 100644 --- a/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp +++ b/tests/auto/render/qshaderprogram/tst_qshaderprogram.cpp @@ -42,6 +42,13 @@ class tst_QShaderProgram : public Qt3DRender::QShaderProgram { Q_OBJECT +public: + tst_QShaderProgram() + : Qt3DRender::QShaderProgram() + { + qRegisterMetaType<Qt3DRender::QShaderProgram::Format>("Format"); + } + private Q_SLOTS: void checkDefaultConstruction() @@ -58,6 +65,7 @@ private Q_SLOTS: QCOMPARE(shaderProgram.computeShaderCode(), QByteArray()); QCOMPARE(shaderProgram.log(), QString()); QCOMPARE(shaderProgram.status(), Qt3DRender::QShaderProgram::NotReady); + QCOMPARE(shaderProgram.format(), Qt3DRender::QShaderProgram::GLSL); } void checkPropertyChanges() @@ -179,6 +187,25 @@ private Q_SLOTS: QCOMPARE(shaderProgram.computeShaderCode(), newValue); QCOMPARE(spy.count(), 0); } + { + // WHEN + QSignalSpy spy(&shaderProgram, SIGNAL(formatChanged(Format))); + const QShaderProgram::Format newValue = QShaderProgram::SPIRV; + shaderProgram.setFormat(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(shaderProgram.format(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + shaderProgram.setFormat(newValue); + + // THEN + QCOMPARE(shaderProgram.format(), newValue); + QCOMPARE(spy.count(), 0); + } } void checkCreationData() @@ -192,6 +219,7 @@ private Q_SLOTS: shaderProgram.setGeometryShaderCode(QByteArrayLiteral("Geometry")); shaderProgram.setFragmentShaderCode(QByteArrayLiteral("Fragment")); shaderProgram.setComputeShaderCode(QByteArrayLiteral("Compute")); + shaderProgram.setFormat(QShaderProgram::SPIRV); // WHEN QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; @@ -214,6 +242,7 @@ private Q_SLOTS: QCOMPARE(shaderProgram.geometryShaderCode(), cloneData.geometryShaderCode); QCOMPARE(shaderProgram.fragmentShaderCode(), cloneData.fragmentShaderCode); QCOMPARE(shaderProgram.computeShaderCode(), cloneData.computeShaderCode); + QCOMPARE(shaderProgram.format(), cloneData.format); QCOMPARE(shaderProgram.id(), creationChangeData->subjectId()); QCOMPARE(shaderProgram.isEnabled(), true); QCOMPARE(shaderProgram.isEnabled(), creationChangeData->isNodeEnabled()); @@ -529,6 +558,42 @@ private Q_SLOTS: // THEN QVERIFY(mainContent.indexOf(includedContent) == 0); } + + void checkFormatPropertyUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DRender::QShaderProgram shaderProgram; + arbiter.setArbiterOnNode(&shaderProgram); + + QSignalSpy spy(&shaderProgram, SIGNAL(formatChanged(Format))); + + // THEN + QVERIFY(spy.isValid()); + + { + // WHEN + shaderProgram.setFormat(QShaderProgram::SPIRV); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(spy.count(), 1); + QCOMPARE(arbiter.events.size(), 0); + + spy.clear(); + } + + { + // WHEN + shaderProgram.setFormat(QShaderProgram::SPIRV); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(spy.count(), 0); + QCOMPARE(arbiter.events.size(), 0); + } + } + }; QTEST_MAIN(tst_QShaderProgram) diff --git a/tests/auto/render/shader/tst_shader.cpp b/tests/auto/render/shader/tst_shader.cpp index 3f0714907..a1f837010 100644 --- a/tests/auto/render/shader/tst_shader.cpp +++ b/tests/auto/render/shader/tst_shader.cpp @@ -42,15 +42,17 @@ private slots: void cleanupLeavesACoherentState(); void dealWithPropertyChanges_data(); void dealWithPropertyChanges(); + void dealWithFormatChanges(); void checkSetRendererDirtyOnInitialization(); void allowToChangeShaderCode_data(); void allowToChangeShaderCode(); }; -Qt3DRender::QShaderProgram *createFrontendShader() +Qt3DRender::QShaderProgram *createFrontendShader(Qt3DRender::QShaderProgram::Format format = Qt3DRender::QShaderProgram::GLSL) { Qt3DRender::QShaderProgram *shader = new Qt3DRender::QShaderProgram(); + shader->setFormat(format); shader->setVertexShaderCode(QByteArrayLiteral( "#version 150"\ @@ -80,6 +82,7 @@ void tst_RenderShader::hasCoherentInitialState() Qt3DRender::Render::Shader *shader = new Qt3DRender::Render::Shader(); QCOMPARE(shader->status(), Qt3DRender::QShaderProgram::NotReady); + QCOMPARE(shader->format(), Qt3DRender::QShaderProgram::GLSL); QVERIFY(shader->log().isEmpty()); QCOMPARE(shader->isDirty(), false); } @@ -97,11 +100,12 @@ void tst_RenderShader::matchesFrontendPeer() for (int i = Qt3DRender::QShaderProgram::Vertex; i <= Qt3DRender::QShaderProgram::Compute; ++i) QCOMPARE(backend.shaderCode()[i], frontend->shaderCode(static_cast<Qt3DRender::QShaderProgram::ShaderType>(i))); + QCOMPARE(backend.format(), frontend->format()); } void tst_RenderShader::cleanupLeavesACoherentState() { - QScopedPointer<Qt3DRender::QShaderProgram> frontend(createFrontendShader()); + QScopedPointer<Qt3DRender::QShaderProgram> frontend(createFrontendShader(Qt3DRender::QShaderProgram::SPIRV)); TestRenderer renderer; Qt3DRender::Render::Shader shader; @@ -112,6 +116,7 @@ void tst_RenderShader::cleanupLeavesACoherentState() QCOMPARE(shader.isDirty(), false); QCOMPARE(shader.status(), Qt3DRender::QShaderProgram::NotReady); + QCOMPARE(shader.format(), Qt3DRender::QShaderProgram::GLSL); } void tst_RenderShader::dealWithPropertyChanges_data() @@ -176,6 +181,45 @@ void tst_RenderShader::dealWithPropertyChanges() QCOMPARE(backend.isDirty(), true); } +void tst_RenderShader::dealWithFormatChanges() +{ + // GIVEN + Qt3DRender::Render::Shader backend; + Qt3DRender::QShaderProgram shader; + TestRenderer renderer; + backend.setRenderer(&renderer); + simulateInitializationSync(&shader, &backend); + + // WHEN + shader.setFormat(Qt3DRender::QShaderProgram::GLSL); + backend.syncFromFrontEnd(&shader, false); + + // THEN + QCOMPARE(backend.format(), Qt3DRender::QShaderProgram::GLSL); + QCOMPARE(backend.isDirty(), false); + QCOMPARE(renderer.dirtyBits(), 0); + + // WHEN + shader.setFormat(Qt3DRender::QShaderProgram::SPIRV); + backend.syncFromFrontEnd(&shader, false); + + // THEN + QCOMPARE(backend.format(), Qt3DRender::QShaderProgram::SPIRV); + QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty); + QCOMPARE(backend.isDirty(), true); + + renderer.resetDirty(); + backend.unsetDirty(); + + // WHEN + shader.setFormat(Qt3DRender::QShaderProgram::SPIRV); + backend.syncFromFrontEnd(&shader, false); + + // THEN + QCOMPARE(backend.isDirty(), false); + QCOMPARE(renderer.dirtyBits(), 0); +} + void tst_RenderShader::checkSetRendererDirtyOnInitialization() { // GIVEN |