summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2015-02-05 10:09:59 +0100
committerSean Harmer <sean.harmer@kdab.com>2015-02-08 15:02:57 +0000
commit8ef268b08c73432ff58985482e67120fc5a9c2c2 (patch)
tree40d004987c7bf0b1d37dae0673e755b478790edb
parent4c01ad4e5df5566d7153056aafbf7b8a70da110b (diff)
QGraphicContext: texture sharing and smart use of TU
Change-Id: I4fb73ac3d03d49be121153235311dd76b47dbd4e Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/qgraphicscontext.cpp73
-rw-r--r--src/render/backend/qgraphicscontext_p.h4
-rw-r--r--src/render/backend/renderview.cpp2
3 files changed, 47 insertions, 32 deletions
diff --git a/src/render/backend/qgraphicscontext.cpp b/src/render/backend/qgraphicscontext.cpp
index 0ff0ad556..706fefceb 100644
--- a/src/render/backend/qgraphicscontext.cpp
+++ b/src/render/backend/qgraphicscontext.cpp
@@ -130,8 +130,8 @@ void QGraphicsContext::initialize()
} else {
QSet<QByteArray> extensions = m_gl->extensions();
m_supportsVAO = extensions.contains(QByteArrayLiteral("GL_OES_vertex_array_object"))
- || extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
- || extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
+ || extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
+ || extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
}
qCDebug(Backend) << "VAO support = " << m_supportsVAO;
}
@@ -361,19 +361,21 @@ void QGraphicsContext::executeCommand(const RenderCommand *)
int QGraphicsContext::activateTexture(TextureScope scope, RenderTexture *tex, int onUnit)
{
- if (onUnit == -1) {
- onUnit = assignUnitForTexture(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
+ onUnit = assignUnitForTexture(tex);
- // check we didn't overflow the available units
- if (onUnit == -1)
- return onUnit;
- }
+ // check we didn't overflow the available units
+ if (onUnit == -1)
+ return -1;
- // actually re-bind if required
- if (m_activeTextures[onUnit] != tex) {
- QOpenGLTexture* glTex = tex->getOrCreateGLTexture();
+ // 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] != tex->dna() || tex->dna() == 0) {
+ QOpenGLTexture *glTex = tex->getOrCreateGLTexture();
glTex->bind(onUnit);
- m_activeTextures[onUnit] = tex;
+ m_activeTextures[onUnit] = tex->dna();
}
int err = m_gl->functions()->glGetError();
@@ -381,9 +383,9 @@ int QGraphicsContext::activateTexture(TextureScope scope, RenderTexture *tex, in
qCWarning(Backend) << "GL error after activating texture" << QString::number(err, 16)
<< tex->textureId() << "on unit" << onUnit;
- m_textureScores[tex] = 200;
+ m_textureScores.insert(m_activeTextures[onUnit], 200);
m_pinnedTextureUnits[onUnit] = true;
- m_textureScopes[onUnit] = scope;
+ m_textureScopes.insert(onUnit, scope);
return onUnit;
}
@@ -396,6 +398,7 @@ void QGraphicsContext::deactivateTexturesWithScope(TextureScope ts)
if (m_textureScopes[u] == ts) {
m_pinnedTextureUnits[u] = false;
+ m_textureScores.insert(m_activeTextures[u], m_textureScores.value(m_activeTextures[u], 1) - 1);
}
} // of units iteration
}
@@ -444,7 +447,7 @@ void QGraphicsContext::resolveHighestOpenGLFunctions()
void QGraphicsContext::deactivateTexture(RenderTexture* tex)
{
for (int u=0; u<m_activeTextures.size(); ++u) {
- if (m_activeTextures[u] == tex) {
+ if (m_activeTextures[u] == tex->dna()) {
Q_ASSERT(m_pinnedTextureUnits[u]);
m_pinnedTextureUnits[u] = false;
return;
@@ -608,18 +611,26 @@ GLuint QGraphicsContext::boundFrameBufferObject()
return m_glHelper->boundFrameBufferObject();
}
+/*!
+ \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 QGraphicsContext::assignUnitForTexture(RenderTexture *tex)
{
int lowestScoredUnit = -1;
int lowestScore = 0xfffffff;
for (int u=0; u<m_activeTextures.size(); ++u) {
- if (m_activeTextures[u] == tex) {
+ if (m_activeTextures[u] == tex->dna())
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_pinnedTextureUnits[u]) {
- int score = m_textureScores[tex];
+ int score = m_textureScores.value(m_activeTextures[u], 0);
if (score < lowestScore) {
lowestScore = score;
lowestScoredUnit = u;
@@ -627,22 +638,24 @@ GLint QGraphicsContext::assignUnitForTexture(RenderTexture *tex)
}
} // of units iteration
- if (lowestScoredUnit == -1) {
- qCWarning(Backend) << Q_FUNC_INFO << "NO free texture units!";
- return GL_INVALID_VALUE;
- }
+ if (lowestScoredUnit == -1)
+ qCWarning(Backend) << Q_FUNC_INFO << "No free texture units!";
return lowestScoredUnit;
}
void QGraphicsContext::decayTextureScores()
{
- // FIXME - very inefficient use of QHash here, both for
- // traversal coherency and subsequent modification.
- Q_FOREACH (RenderTexture* t, m_textureScores.keys()) {
- if ((m_textureScores[t]--) <= 0) {
- qCDebug(Backend) << "removing inactive texture" << t;
- m_textureScores.remove((t));
+ QHash<uint, int>::iterator it = m_textureScores.begin();
+ const QHash<uint, int>::iterator end = m_textureScores.end();
+
+ while (it != end) {
+ it.value()--;
+ if (it.value() <= 0) {
+ qCDebug(Backend) << "removing inactive texture" << it.key();
+ it = m_textureScores.erase(it);
+ } else {
+ ++it;
}
}
}
@@ -664,8 +677,10 @@ void QGraphicsContext::setUniforms(QUniformPack &uniforms)
{
// Activate textures and update TextureUniform in the pack
// with the correct textureUnit
- deactivateTexturesWithScope(TextureScopeMaterial);
+ // Set the pinned texture of the previous material texture
+ // to pinable so that we should easily find an available texture unit
+ deactivateTexturesWithScope(TextureScopeMaterial);
// Update the uniforms with the correct texture unit id's
QHash<QString, const QUniformValue *> &uniformValues = uniforms.uniforms();
for (int i = 0; i < uniforms.textures().size(); ++i) {
diff --git a/src/render/backend/qgraphicscontext_p.h b/src/render/backend/qgraphicscontext_p.h
index b8ba270de..d7636aea2 100644
--- a/src/render/backend/qgraphicscontext_p.h
+++ b/src/render/backend/qgraphicscontext_p.h
@@ -214,13 +214,13 @@ private:
QHash<GLuint, QSize> m_renderTargetsSize;
// active textures, indexed by texture unit
- QVector<RenderTexture *> m_activeTextures;
+ QVector<uint> m_activeTextures;
QBitArray m_pinnedTextureUnits;
QVector<TextureScope> m_textureScopes;
// recency score for all render-textures we've seen. Higher scores
// mean more recently used.
- QHash<RenderTexture *, int> m_textureScores;
+ QHash<uint, int> m_textureScores;
RenderMaterial* m_material;
QRectF m_viewport;
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 9f3f480af..f1a6cd3aa 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -335,7 +335,7 @@ void RenderView::sort()
while (it != uniforms.end()) {
bool found = false;
- if (cachedUniforms.contains(it.key())) {
+ if (cachedUniforms.contains(it.key()) && !it.value()->isTexture()) {
const QUniformValue *refValue = cachedUniforms[it.key()];
if (*const_cast<QUniformValue *>(refValue) == *it.value()) {
cachedUniforms.insert(it.key(), it.value());