diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2019-04-14 17:26:22 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@qt.io> | 2019-04-15 14:30:59 +0000 |
commit | bad9cd31fc9f3bb911f59439c0468f8dc7170646 (patch) | |
tree | 60d5a6afcd93a3adeb2f324dfa7d4e8bab6a8735 /src/render/renderers/opengl | |
parent | 100175e92d6adb346169eda0392b9485ca41a905 (diff) | |
parent | 276be935bfeccde733bacd4267abeb978f6efda5 (diff) |
Merge remote-tracking branch origin/5.13 into dev
Change-Id: Ib5c04e9941aeea1a4cd27519b94b9a53e8349ea3
Diffstat (limited to 'src/render/renderers/opengl')
13 files changed, 382 insertions, 238 deletions
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp index 01a1b107a..9bbb5fc5e 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp @@ -130,6 +130,7 @@ GraphicsContext::GraphicsContext() , m_glHelper(nullptr) , m_shaderCache(nullptr) , m_debugLogger(nullptr) + , m_currentVAO(nullptr) { } @@ -199,15 +200,20 @@ bool GraphicsContext::makeCurrent(QSurface *surface) return false; } + initializeHelpers(surface); + + return true; +} + +void GraphicsContext::initializeHelpers(QSurface *surface) +{ // Set the correct GL Helper depending on the surface // If no helper exists, create one - m_glHelper = m_glHelpers.value(surface); if (!m_glHelper) { m_glHelper = resolveHighestOpenGLFunctions(); m_glHelpers.insert(surface, m_glHelper); } - return true; } void GraphicsContext::doneCurrent() diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h index 548a6d9f4..9a9f1416b 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h @@ -179,6 +179,7 @@ public: bool supportsVAO() const { return m_supportsVAO; } void initialize(); + void initializeHelpers(QSurface *surface); GraphicsHelperInterface *resolveHighestOpenGLFunctions(); bool m_initialized; diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri index 5c9479d2b..ad08038c9 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri @@ -3,6 +3,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/glfence_p.h \ $$PWD/graphicscontext_p.h \ $$PWD/graphicshelperinterface_p.h \ $$PWD/graphicshelperes2_p.h \ @@ -14,7 +15,7 @@ HEADERS += \ $$PWD/graphicshelpergl4_p.h \ $$PWD/graphicshelpergl3_2_p.h \ $$PWD/submissioncontext_p.h \ - $$PWD/glfence_p.h + $$PWD/texturesubmissioncontext_p.h SOURCES += \ $$PWD/graphicscontext.cpp \ @@ -26,4 +27,5 @@ SOURCES += \ $$PWD/graphicshelpergl3_3.cpp \ $$PWD/graphicshelpergl4.cpp \ $$PWD/graphicshelpergl3_2.cpp \ - $$PWD/submissioncontext.cpp + $$PWD/submissioncontext.cpp \ + $$PWD/texturesubmissioncontext.cpp diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index a39b900e0..d3bc46c12 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -49,6 +49,7 @@ #include <Qt3DRender/private/buffer_p.h> #include <Qt3DRender/private/attribute_p.h> #include <Qt3DRender/private/rendercommand_p.h> +#include <Qt3DRender/private/renderstates_p.h> #include <Qt3DRender/private/renderstateset_p.h> #include <Qt3DRender/private/rendertarget_p.h> #include <Qt3DRender/private/graphicshelperinterface_p.h> @@ -96,40 +97,18 @@ namespace Qt3DRender { namespace Render { -class TextureExtRendererLocker +static QHash<unsigned int, SubmissionContext*> static_contexts; + +unsigned int nextFreeContextId() { -public: - static void lock(GLTexture *tex) - { - if (!tex->isExternalRenderingEnabled()) - return; - if (s_lockHash.keys().contains(tex)) { - ++s_lockHash[tex]; - } else { - tex->externalRenderingLock()->lock(); - s_lockHash[tex] = 1; - } - } - static void unlock(GLTexture *tex) - { - if (!tex->isExternalRenderingEnabled()) - return; - if (!s_lockHash.keys().contains(tex)) - return; - - --s_lockHash[tex]; - if (s_lockHash[tex] == 0) { - s_lockHash.remove(tex); - tex->externalRenderingLock()->unlock(); - } + for (unsigned int i=0; i < 0xffff; ++i) { + if (!static_contexts.contains(i)) + return i; } -private: - static QHash<GLTexture*, int> s_lockHash; -}; - -QHash<GLTexture*, int> TextureExtRendererLocker::s_lockHash = QHash<GLTexture*, int>(); -static QHash<unsigned int, SubmissionContext*> static_contexts; + qFatal("Couldn't find free context ID"); + return 0; +} namespace { @@ -376,16 +355,6 @@ void applyStateHelper<LineWidth>(const LineWidth *state, SubmissionContext *gc) } // anonymous -unsigned int nextFreeContextId() -{ - for (unsigned int i=0; i < 0xffff; ++i) { - if (!static_contexts.contains(i)) - return i; - } - - qFatal("Couldn't find free context ID"); - return 0; -} SubmissionContext::SubmissionContext() : GraphicsContext() @@ -404,7 +373,6 @@ SubmissionContext::SubmissionContext() , m_stateSet(nullptr) , m_renderer(nullptr) , m_uboTempArray(QByteArray(1024, 0)) - , m_currentVAO(nullptr) { static_contexts[m_id] = this; } @@ -420,7 +388,7 @@ SubmissionContext::~SubmissionContext() void SubmissionContext::initialize() { GraphicsContext::initialize(); - m_activeTextures.resize(maxTextureUnitsCount()); + m_textureContext.initialize(this); } void SubmissionContext::resolveRenderTargetFormat() @@ -472,10 +440,6 @@ bool SubmissionContext::beginDrawing(QSurface *surface) // TODO: cache surface format somewhere rather than doing this every time render surface changes resolveRenderTargetFormat(); - // Sets or Create the correct m_glHelper - // for the current surface - activateGLHelper(); - #if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) GLint err = m_gl->functions()->glGetError(); if (err != 0) { @@ -485,22 +449,18 @@ bool SubmissionContext::beginDrawing(QSurface *surface) if (!isInitialized()) initialize(); + initializeHelpers(m_surface); // need to reset these values every frame, may get overwritten elsewhere m_gl->functions()->glClearColor(m_currClearColorValue.redF(), m_currClearColorValue.greenF(), m_currClearColorValue.blueF(), m_currClearColorValue.alphaF()); m_gl->functions()->glClearDepthf(m_currClearDepthValue); m_gl->functions()->glClearStencil(m_currClearStencilValue); - if (m_activeShader) { m_activeShader = nullptr; m_activeShaderDNA = 0; } - // reset active textures - for (int u = 0; u < m_activeTextures.size(); ++u) - m_activeTextures[u].texture = nullptr; - m_boundArrayBuffer = nullptr; static int callCount = 0; @@ -518,10 +478,7 @@ void SubmissionContext::endDrawing(bool swapBuffers) m_gl->swapBuffers(m_surface); if (m_ownCurrent) m_gl->doneCurrent(); - decayTextureScores(); - for (int i = 0; i < m_activeTextures.size(); ++i) - if (m_activeTextures[i].texture) - TextureExtRendererLocker::unlock(m_activeTextures[i].texture); + m_textureContext.endDrawing(); } void SubmissionContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, GLuint defaultFboId) @@ -825,20 +782,6 @@ void SubmissionContext::setOpenGLContext(QOpenGLContext* ctx) m_gl = ctx; } -void SubmissionContext::activateGLHelper() -{ - // Sets the correct GL Helper depending on the surface - // If no helper exists, create one - m_glHelper = m_glHelpers.value(m_surface); - if (!m_glHelper) { - m_glHelper = resolveHighestOpenGLFunctions(); - m_glHelpers.insert(m_surface, m_glHelper); - // Note: OpenGLContext is current at this point - m_gl->functions()->glDisable(GL_DITHER); - } -} - - // Called only from RenderThread bool SubmissionContext::activateShader(ProgramDNA shaderDNA) { @@ -920,126 +863,10 @@ void SubmissionContext::setActiveMaterial(Material *rmat) if (m_material == rmat) return; - deactivateTexturesWithScope(TextureScopeMaterial); + m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial); m_material = rmat; } -int SubmissionContext::activateTexture(TextureScope scope, GLTexture *tex, int onUnit) -{ - // Returns the texture unit to use for the texture - // This always return a valid unit, unless there are more textures than - // texture unit available for the current material - onUnit = assignUnitForTexture(tex); - - // check we didn't overflow the available units - if (onUnit == -1) - return -1; - - // actually re-bind if required, the tex->dna on the unit not being the same - // Note: tex->dna() could be 0 if the texture has not been created yet - if (m_activeTextures[onUnit].texture != tex) { - // Texture must have been created and updated at this point - - const int sharedTextureId = tex->sharedTextureId(); - - // We have a valid texture id provided by a shared context - if (sharedTextureId > 0) { - m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit); - const QAbstractTexture::Target target = tex->properties().target; - // For now we know that target values correspond to the GL values - m_gl->functions()->glBindTexture(target, tex->sharedTextureId()); - } else { - QOpenGLTexture *glTex = tex->getGLTexture(); - if (glTex == nullptr) - return -1; - glTex->bind(onUnit); - } - - if (m_activeTextures[onUnit].texture) - TextureExtRendererLocker::unlock(m_activeTextures[onUnit].texture); - m_activeTextures[onUnit].texture = tex; - TextureExtRendererLocker::lock(tex); - } - -#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) - int err = m_gl->functions()->glGetError(); - if (err) - qCWarning(Backend) << "GL error after activating texture" << QString::number(err, 16) - << tex->getGLTexture()->textureId() << "on unit" << onUnit; -#endif - - m_activeTextures[onUnit].score = 200; - m_activeTextures[onUnit].pinned = true; - m_activeTextures[onUnit].scope = scope; - - return onUnit; -} - -void SubmissionContext::deactivateTexturesWithScope(TextureScope ts) -{ - for (int u=0; u<m_activeTextures.size(); ++u) { - if (!m_activeTextures[u].pinned) - continue; // inactive, ignore - - if (m_activeTextures[u].scope == ts) { - m_activeTextures[u].pinned = false; - m_activeTextures[u].score = qMax(m_activeTextures[u].score, 1) - 1; - } - } // of units iteration -} - -void SubmissionContext::deactivateTexture(GLTexture* tex) -{ - for (int u=0; u<m_activeTextures.size(); ++u) { - if (m_activeTextures[u].texture == tex) { - Q_ASSERT(m_activeTextures[u].pinned); - m_activeTextures[u].pinned = false; - return; - } - } // of units iteration - - qCWarning(Backend) << Q_FUNC_INFO << "texture not active:" << tex; -} - -/*! - \internal - Returns a texture unit for a texture, -1 if all texture units are assigned. - Tries to use the texture unit with the texture that hasn't been used for the longest time - if the texture happens not to be already pinned on a texture unit. - */ -GLint SubmissionContext::assignUnitForTexture(GLTexture *tex) -{ - int lowestScoredUnit = -1; - int lowestScore = 0xfffffff; - - for (int u=0; u<m_activeTextures.size(); ++u) { - if (m_activeTextures[u].texture == tex) - return u; - - // No texture is currently active on the texture unit - // we save the texture unit with the texture that has been on there - // the longest time while not being used - if (!m_activeTextures[u].pinned) { - int score = m_activeTextures[u].score; - if (score < lowestScore) { - lowestScore = score; - lowestScoredUnit = u; - } - } - } // of units iteration - - if (lowestScoredUnit == -1) - qCWarning(Backend) << Q_FUNC_INFO << "No free texture units!"; - - return lowestScoredUnit; -} - -void SubmissionContext::decayTextureScores() -{ - for (int u = 0; u < m_activeTextures.size(); u++) - m_activeTextures[u].score = qMax(m_activeTextures[u].score - 1, 0); -} - void SubmissionContext::setCurrentStateSet(RenderStateSet *ss) { if (ss == m_stateSet) @@ -1329,7 +1156,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) // to pinable so that we should easily find an available texture unit NodeManagers *manager = m_renderer->nodeManagers(); - deactivateTexturesWithScope(TextureScopeMaterial); + m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial); // Update the uniforms with the correct texture unit id's PackUniformHash &uniformValues = parameterPack.uniforms(); @@ -1341,7 +1168,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (t != nullptr) { UniformValue &texUniform = uniformValues[namedTex.glslNameId]; if (texUniform.valueType() == UniformValue::TextureValue) { - const int texUnit = activateTexture(TextureScopeMaterial, t); + const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, m_gl, t); texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; if (texUnit == -1) { if (namedTex.glslNameId != irradianceId && diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h index dbfaef148..844e62f15 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h @@ -54,6 +54,7 @@ #include <Qt3DRender/private/graphicscontext_p.h> +#include <Qt3DRender/private/texturesubmissioncontext_p.h> #include <Qt3DRender/qclearbuffers.h> #include <Qt3DRender/private/glbuffer_p.h> #include <Qt3DRender/qattribute.h> @@ -82,13 +83,6 @@ class Buffer; class ShaderManager; struct StateVariant; -enum TextureScope -{ - TextureScopeMaterial = 0, - TextureScopeTechnique - // per-pass for deferred rendering? -}; - typedef QPair<QString, int> NamedUniformLocation; class Q_AUTOTEST_EXPORT SubmissionContext : public GraphicsContext @@ -102,7 +96,6 @@ public: bool beginDrawing(QSurface *surface); void endDrawing(bool swapBuffers); - void activateGLHelper(); void releaseOpenGL(); void setOpenGLContext(QOpenGLContext* ctx); @@ -126,11 +119,6 @@ public: QRenderTargetOutput::AttachmentPoint outputAttachmentPoint, QBlitFramebuffer::InterpolationMethod interpolationMethod); - - // Material - Material* activeMaterial() const { return m_material; } - void setActiveMaterial(Material* rmat); - // Attributes void specifyAttribute(const Attribute *attribute, Buffer *buffer, @@ -147,10 +135,6 @@ public: // Parameters bool setParameters(ShaderParameterPack ¶meterPack); - // Textures - int activateTexture(TextureScope scope, GLTexture* tex, int onUnit = -1); - void deactivateTexture(GLTexture *tex); - // RenderState void setCurrentStateSet(RenderStateSet* ss); RenderStateSet *currentStateSet() const; @@ -175,10 +159,9 @@ public: private: void initialize(); - // Textures - void decayTextureScores(); - GLint assignUnitForTexture(GLTexture* tex); - void deactivateTexturesWithScope(TextureScope ts); + // Material + Material* activeMaterial() const { return m_material; } + void setActiveMaterial(Material* rmat); // FBO void bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments); @@ -187,7 +170,6 @@ private: GLuint createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments); GLuint updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, bool isActiveRenderTarget); - // Buffers HGLBuffer createGLBufferFor(Buffer *buffer, GLBuffer::Type type); void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false); @@ -207,17 +189,6 @@ private: QHash<GLuint, QSize> m_renderTargetsSize; QAbstractTexture::TextureFormat m_renderTargetFormat; - QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers; - - // active textures, indexed by texture unit - struct ActiveTexture { - GLTexture *texture = nullptr; - int score = 0; - TextureScope scope = TextureScopeMaterial; - bool pinned = false; - }; - QVector<ActiveTexture> m_activeTextures; - // cache some current state, to make sure we don't issue unnecessary GL calls int m_currClearStencilValue; float m_currClearDepthValue; @@ -232,10 +203,10 @@ private: Renderer *m_renderer; QByteArray m_uboTempArray; + TextureSubmissionContext m_textureContext; // Attributes friend class OpenGLVertexArrayObject; - OpenGLVertexArrayObject *m_currentVAO; struct VAOVertexAttribute { diff --git a/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp new file mode 100644 index 000000000..67d0f9976 --- /dev/null +++ b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "texturesubmissioncontext_p.h" + +#include <Qt3DRender/private/graphicscontext_p.h> +#include <Qt3DRender/private/gltexture_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class TextureExtRendererLocker +{ +public: + static void lock(GLTexture *tex) + { + if (!tex->isExternalRenderingEnabled()) + return; + if (s_lockHash.keys().contains(tex)) { + ++s_lockHash[tex]; + } else { + tex->externalRenderingLock()->lock(); + s_lockHash[tex] = 1; + } + } + static void unlock(GLTexture *tex) + { + if (!tex->isExternalRenderingEnabled()) + return; + if (!s_lockHash.keys().contains(tex)) + return; + + --s_lockHash[tex]; + if (s_lockHash[tex] == 0) { + s_lockHash.remove(tex); + tex->externalRenderingLock()->unlock(); + } + } +private: + static QHash<GLTexture*, int> s_lockHash; +}; + +QHash<GLTexture*, int> TextureExtRendererLocker::s_lockHash = QHash<GLTexture*, int>(); + + +TextureSubmissionContext::TextureSubmissionContext() +{ + +} + +TextureSubmissionContext::~TextureSubmissionContext() +{ + +} + +void TextureSubmissionContext::initialize(GraphicsContext *context) +{ + m_activeTextures.resize(context->maxTextureUnitsCount()); +} + +void TextureSubmissionContext::endDrawing() +{ + decayTextureScores(); + for (int i = 0; i < m_activeTextures.size(); ++i) + if (m_activeTextures[i].texture) + TextureExtRendererLocker::unlock(m_activeTextures[i].texture); +} + +int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureScope scope, + QOpenGLContext *m_gl, + GLTexture *tex) +{ + // Returns the texture unit to use for the texture + // This always return a valid unit, unless there are more textures than + // texture unit available for the current material + const int onUnit = assignUnitForTexture(tex); + + // check we didn't overflow the available units + if (onUnit == -1) + return -1; + + const int sharedTextureId = tex->sharedTextureId(); + // We have a valid texture id provided by a shared context + if (sharedTextureId > 0) { + m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit); + const QAbstractTexture::Target target = tex->properties().target; + // For now we know that target values correspond to the GL values + m_gl->functions()->glBindTexture(target, tex->sharedTextureId()); + } else { + // Texture must have been created and updated at this point + QOpenGLTexture *glTex = tex->getGLTexture(); + if (glTex == nullptr) + return -1; + glTex->bind(uint(onUnit)); + } + if (m_activeTextures[onUnit].texture != tex) { + if (m_activeTextures[onUnit].texture) + TextureExtRendererLocker::unlock(m_activeTextures[onUnit].texture); + m_activeTextures[onUnit].texture = tex; + TextureExtRendererLocker::lock(tex); + } + +#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) + int err = m_gl->functions()->glGetError(); + if (err) + qCWarning(Backend) << "GL error after activating texture" << QString::number(err, 16) + << tex->getGLTexture()->textureId() << "on unit" << onUnit; +#endif + + m_activeTextures[onUnit].score = 200; + m_activeTextures[onUnit].pinned = true; + m_activeTextures[onUnit].scope = scope; + + return onUnit; +} + +void TextureSubmissionContext::deactivateTexturesWithScope(TextureSubmissionContext::TextureScope ts) +{ + for (int u=0; u<m_activeTextures.size(); ++u) { + if (!m_activeTextures[u].pinned) + continue; // inactive, ignore + + if (m_activeTextures[u].scope == ts) { + m_activeTextures[u].pinned = false; + m_activeTextures[u].score = qMax(m_activeTextures[u].score, 1) - 1; + } + } // of units iteration +} + +void TextureSubmissionContext::deactivateTexture(GLTexture* tex) +{ + for (int u=0; u<m_activeTextures.size(); ++u) { + if (m_activeTextures[u].texture == tex) { + Q_ASSERT(m_activeTextures[u].pinned); + m_activeTextures[u].pinned = false; + return; + } + } // of units iteration + + qCWarning(Backend) << Q_FUNC_INFO << "texture not active:" << tex; +} + +/*! + \internal + Returns a texture unit for a texture, -1 if all texture units are assigned. + Tries to use the texture unit with the texture that hasn't been used for the longest time + if the texture happens not to be already pinned on a texture unit. + */ +int TextureSubmissionContext::assignUnitForTexture(GLTexture *tex) +{ + int lowestScoredUnit = -1; + int lowestScore = 0xfffffff; + + for (int u=0; u<m_activeTextures.size(); ++u) { + if (m_activeTextures[u].texture == tex) + return u; + } + + for (int u=0; u<m_activeTextures.size(); ++u) { + // No texture is currently active on the texture unit + // we save the texture unit with the texture that has been on there + // the longest time while not being used + if (!m_activeTextures[u].pinned) { + int score = m_activeTextures[u].score; + if (score < lowestScore) { + lowestScore = score; + lowestScoredUnit = u; + } + } + } // of units iteration + + if (lowestScoredUnit == -1) + qCWarning(Backend) << Q_FUNC_INFO << "No free texture units!"; + + return lowestScoredUnit; +} + +void TextureSubmissionContext::decayTextureScores() +{ + for (int u = 0; u < m_activeTextures.size(); u++) + m_activeTextures[u].score = qMax(m_activeTextures[u].score - 1, 0); +} + +} // namespace Render +} // namespace Qt3DRender of namespace + +QT_END_NAMESPACE diff --git a/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h new file mode 100644 index 000000000..3c84fe558 --- /dev/null +++ b/src/render/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H +#define QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include <qglobal.h> +#include <QVector> + +QT_BEGIN_NAMESPACE + +class QOpenGLContext; + +namespace Qt3DRender { +namespace Render { + +class GraphicsContext; +class GLTexture; + +class Q_AUTOTEST_EXPORT TextureSubmissionContext +{ +public: + enum TextureScope + { + TextureScopeMaterial = 0, + TextureScopeTechnique + // per-pass for deferred rendering? + }; + + TextureSubmissionContext(); + ~TextureSubmissionContext(); + + void initialize(GraphicsContext *context); + void endDrawing(); + int activateTexture(TextureScope scope, QOpenGLContext *gl, GLTexture* tex); + void deactivateTexture(GLTexture *tex); + void deactivateTexturesWithScope(TextureScope ts); + +private: + void decayTextureScores(); + int assignUnitForTexture(GLTexture* tex); + + // active textures, indexed by texture unit + struct ActiveTexture { + GLTexture *texture = nullptr; + int score = 0; + TextureScope scope = TextureScopeMaterial; + bool pinned = false; + }; + QVector<ActiveTexture> m_activeTextures; +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H diff --git a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h index 4f7a7146c..27b3d4ed2 100644 --- a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h +++ b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob_p.h @@ -64,7 +64,7 @@ namespace Render { class TechniqueManager; class Renderer; -class QT3DRENDERSHARED_PRIVATE_EXPORT FilterCompatibleTechniqueJob : public Qt3DCore::QAspectJob +class Q_3DRENDERSHARED_PRIVATE_EXPORT FilterCompatibleTechniqueJob : public Qt3DCore::QAspectJob { public: FilterCompatibleTechniqueJob(); diff --git a/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h b/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h index fbfac3364..6ba060841 100644 --- a/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h +++ b/src/render/renderers/opengl/jobs/materialparametergathererjob_p.h @@ -70,7 +70,7 @@ class Renderer; // TO be executed for each FrameGraph branch with a given RenderPassFilter/TechniqueFilter -class QT3DRENDERSHARED_PRIVATE_EXPORT MaterialParameterGathererJob : public Qt3DCore::QAspectJob +class Q_3DRENDERSHARED_PRIVATE_EXPORT MaterialParameterGathererJob : public Qt3DCore::QAspectJob { public: MaterialParameterGathererJob(); diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index a3c0b93da..012ec7056 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -1656,7 +1656,6 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren ViewSubmissionResultData resultData; resultData.lastBoundFBOId = lastBoundFBOId; resultData.surface = lastUsedSurface; - return resultData; } @@ -1796,14 +1795,16 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() renderBinJobs.push_back(m_textureGathererJob); - // Layer cache is dependent on layers, layer filters and the enabled flag - // on entities + // Layer cache is dependent on layers, layer filters (hence FG structure + // changes) and the enabled flag on entities + const bool frameGraphDirty = dirtyBitsForFrame & AbstractRenderer::FrameGraphDirty; const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty; - const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty; + const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty || frameGraphDirty; const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty; const bool lightsDirty = dirtyBitsForFrame & AbstractRenderer::LightsDirty; const bool computeableDirty = dirtyBitsForFrame & AbstractRenderer::ComputeDirty; const bool renderableDirty = dirtyBitsForFrame & AbstractRenderer::GeometryDirty; + const bool materialCacheNeedsToBeRebuilt = materialDirty || frameGraphDirty; // Rebuild Entity Layers list if layers are dirty if (layersDirty) @@ -1830,11 +1831,10 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() for (int i = 0; i < fgBranchCount; ++i) { RenderViewBuilder builder(fgLeaves.at(i), i, this); builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt); - builder.setMaterialGathererCacheNeedsToBeRebuilt(materialDirty); builder.setRenderableCacheNeedsToBeRebuilt(renderableDirty); builder.setComputableCacheNeedsToBeRebuilt(computeableDirty); builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty); - + builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt); builder.prepareJobs(); renderBinJobs.append(builder.buildJobHierachy()); } @@ -1845,6 +1845,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() // FilterLayerEntityJob is part of the RenderViewBuilder jobs and must be run later // if none of those jobs are started this frame notCleared |= AbstractRenderer::EntityEnabledDirty; + notCleared |= AbstractRenderer::FrameGraphDirty; notCleared |= AbstractRenderer::LayersDirty; } diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h index a80a862f7..9a2c99c30 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -157,7 +157,7 @@ typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; using IntrospectShadersJobPtr = GenericLambdaJobPtr<std::function<void()>>; -class QT3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer +class Q_3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer { public: explicit Renderer(QRenderAspect::RenderType type); @@ -190,6 +190,7 @@ public: Entity *sceneRoot() const override { return m_renderSceneRoot; } FrameGraphNode *frameGraphRoot() const override; + RenderQueue *renderQueue() const { return m_renderQueue; } void markDirty(BackendNodeDirtySet changes, BackendNode *node) override; BackendNodeDirtySet dirtyBits() override; diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index ff43e74f4..8626d0125 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -102,9 +102,10 @@ int LIGHT_COLOR_NAMES[MAX_LIGHTS]; int LIGHT_INTENSITY_NAMES[MAX_LIGHTS]; QString LIGHT_STRUCT_NAMES[MAX_LIGHTS]; +bool wasInitialized = false; + } // anonymous namespace -bool wasInitialized = false; RenderView::StandardUniformsNameToTypeHash RenderView::ms_standardUniformSetters; diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp index 0ec4d8041..83fab301a 100644 --- a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp @@ -47,7 +47,10 @@ namespace Qt3DRender { namespace Render { -const int RenderViewBuilder::m_optimalParallelJobCount = std::max(QThread::idealThreadCount(), 2); +// In some cases having less jobs is better (especially on fast cpus where +// splitting just adds more overhead). Ideally, we should try to set the value +// depending on the platform/CPU/nbr of cores +const int RenderViewBuilder::m_optimalParallelJobCount = std::max(std::min(4, QThread::idealThreadCount()), 2); namespace { |