diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-09-03 11:59:24 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-09-09 20:42:38 +0200 |
commit | 7af6649e884f4ba9fa3fde0333090b93f62a13c0 (patch) | |
tree | 50c8123a114b6f29a949c910751ce999e9bc7c81 /src/gui/rhi/qrhigles2.cpp | |
parent | 89d0a03c067b42155b1a2d310f8514f595abfd61 (diff) |
rhi: gl, metal, d3d: Reuse shader objects when source is the same
Now that Qt Quick's batch renderer misses one level of shader source
caching due to the nature of pipeline state objects, it can be useful
to keep and reuse shader objects when the hash of the source code
matches.
The goal here is to allow Qt Quick to be on par with what the direct
OpenGL path has when it comes to caching shader sources and compilation
results. The program binary disk cache is not in scope in this patch.
Also adds QRhi::releaseCachedResources(), similarly to what the scenegraph
has. This can be called to clear caches such as the shader object
cache we keep here.
Change-Id: Ie3d81d823f61fa65ec814439e882c498f7774d43
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhigles2.cpp')
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index f4e711e33e..9ad591a17a 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -502,6 +502,10 @@ void QRhiGles2::destroy() ensureContext(); executeDeferredReleases(); + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); + m_shaderCache.clear(); + if (!importedContext) { delete ctx; ctx = nullptr; @@ -757,6 +761,17 @@ void QRhiGles2::makeThreadLocalNativeContextCurrent() ensureContext(); } +void QRhiGles2::releaseCachedResources() +{ + if (!ensureContext()) + return; + + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); + + m_shaderCache.clear(); +} + QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { @@ -2673,7 +2688,6 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type) bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderDescription *desc, int *glslVersionUsed) { - GLuint shader = f->glCreateShader(toGlShaderType(shaderStage.type())); const QShader bakedShader = shaderStage.shader(); QVector<int> versionsToTry; QByteArray source; @@ -2733,27 +2747,40 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage return false; } - const char *srcStr = source.constData(); - const GLint srcLength = source.count(); - f->glShaderSource(shader, 1, &srcStr, &srcLength); - f->glCompileShader(shader); - GLint compiled = 0; - f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLogLength = 0; - f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); - QByteArray log; - if (infoLogLength > 1) { - GLsizei length = 0; - log.resize(infoLogLength); - f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data()); + GLuint shader; + auto cacheIt = m_shaderCache.constFind(shaderStage); + if (cacheIt != m_shaderCache.constEnd()) { + shader = *cacheIt; + } else { + shader = f->glCreateShader(toGlShaderType(shaderStage.type())); + const char *srcStr = source.constData(); + const GLint srcLength = source.count(); + f->glShaderSource(shader, 1, &srcStr, &srcLength); + f->glCompileShader(shader); + GLint compiled = 0; + f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLogLength = 0; + f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + QByteArray log; + if (infoLogLength > 1) { + GLsizei length = 0; + log.resize(infoLogLength); + f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data()); + } + qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData()); + return false; } - qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData()); - return false; + if (m_shaderCache.count() >= MAX_SHADER_CACHE_ENTRIES) { + // Use the simplest strategy: too many cached shaders -> drop them all. + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); // does not actually get released yet when attached to a not-yet-released program + m_shaderCache.clear(); + } + m_shaderCache.insert(shaderStage, shader); } f->glAttachShader(program, shader); - f->glDeleteShader(shader); *desc = bakedShader.description(); return true; |