summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qrhigles2.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-09-26 14:56:32 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-09-30 20:07:28 +0200
commite1ed2c3864e2b9aeeebec25de60ab62eb254b591 (patch)
treeb572f740f973b55d268ffe23a85420cc05e77ebd /src/gui/rhi/qrhigles2.cpp
parent6f9a215cc4c4fa87e5692174dd728b521513ecd2 (diff)
Share and enable shader disk cache in QRhi OpenGL backend
The expectation for it is to function identically to what we get with QOpenGLShaderProgram. (same environment variables, same logging categories, etc.). QOpenGLProgramBinaryCache is now shared between the QOpenGL convenience classes (like QOpenGLShaderProgram) and QRhi. To achieve more modularity and to prepare for QOpenGLShaderProgram and friends moving out of QtGui, this class cannot depend on QOpenGLShader* anymore. This involves adding some minor conversions between QRhi and QOpenGL enums for example. Change-Id: I2f4664e074823ea536281aea8006a6db159a7381 Reviewed-by: Christian Strømme <christian.stromme@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhigles2.cpp')
-rw-r--r--src/gui/rhi/qrhigles2.cpp124
1 files changed, 111 insertions, 13 deletions
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index dfa0351a8d..11beda5b92 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -39,6 +39,7 @@
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtGui/private/qopenglextensions_p.h>
+#include <QtGui/private/qopenglprogrambinarycache_p.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
@@ -275,6 +276,8 @@ QT_BEGIN_NAMESPACE
#define GL_POINT_SPRITE 0x8861
#endif
+Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
+
/*!
Constructs a new QRhiGles2InitParams.
@@ -2709,8 +2712,7 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
}
}
-bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
- QShaderDescription *desc, int *glslVersionUsed)
+QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
{
const QShader bakedShader = shaderStage.shader();
QVector<int> versionsToTry;
@@ -2729,8 +2731,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
QShaderVersion ver(v, QShaderVersion::GlslEs);
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
- if (glslVersionUsed)
- *glslVersionUsed = v;
+ if (glslVersion)
+ *glslVersion = v;
break;
}
}
@@ -2759,8 +2761,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
for (int v : versionsToTry) {
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
- if (glslVersionUsed)
- *glslVersionUsed = v;
+ if (glslVersion)
+ *glslVersion = v;
break;
}
}
@@ -2768,8 +2770,15 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
if (source.isEmpty()) {
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
<< ") in baked shader" << bakedShader;
- return false;
}
+ return source;
+}
+
+bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion)
+{
+ const QByteArray source = shaderSource(shaderStage, glslVersion);
+ if (source.isEmpty())
+ return false;
GLuint shader;
auto cacheIt = m_shaderCache.constFind(shaderStage);
@@ -2806,7 +2815,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
f->glAttachShader(program, shader);
- *desc = bakedShader.description();
return true;
}
@@ -2861,6 +2869,68 @@ void QRhiGles2::gatherSamplers(GLuint program, const QShaderDescription::InOutVa
}
}
+bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
+{
+ static QOpenGLProgramBinarySupportCheckWrapper checker;
+ return checker.get(ctx)->isSupported();
+}
+
+static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
+
+static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
+{
+ switch (type) {
+ case QRhiShaderStage::Vertex:
+ return QShader::VertexStage;
+ case QRhiShaderStage::Fragment:
+ return QShader::FragmentStage;
+ case QRhiShaderStage::Compute:
+ return QShader::ComputeStage;
+ default:
+ Q_UNREACHABLE();
+ return QShader::VertexStage;
+ }
+}
+
+QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
+ GLuint program, QByteArray *cacheKey)
+{
+ QRhiGles2::DiskCacheResult result = QRhiGles2::DiskCacheMiss;
+ QByteArray diskCacheKey;
+
+ if (isProgramBinaryDiskCacheEnabled()) {
+ QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
+ for (int i = 0; i < stageCount; ++i) {
+ const QRhiShaderStage &stage(stages[i]);
+ const QByteArray source = shaderSource(stage, nullptr);
+ if (source.isEmpty())
+ return QRhiGles2::DiskCacheError;
+ binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(toShaderStage(stage.type()), source));
+ }
+
+ diskCacheKey = binaryProgram.cacheKey();
+ if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
+ program, diskCacheKey.constData());
+ result = QRhiGles2::DiskCacheHit;
+ }
+ }
+
+ if (cacheKey)
+ *cacheKey = diskCacheKey;
+
+ return result;
+}
+
+void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
+{
+ if (isProgramBinaryDiskCacheEnabled()) {
+ qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
+ program, cacheKey.constData());
+ qrhi_programBinaryCache.save(cacheKey, program);
+ }
+}
+
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
: QRhiBuffer(rhi, type, usage, size)
{
@@ -3547,17 +3617,29 @@ bool QGles2GraphicsPipeline::build()
program = rhiD->f->glCreateProgram();
+ QByteArray diskCacheKey;
+ QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(m_shaderStages.constData(),
+ m_shaderStages.count(),
+ program,
+ &diskCacheKey);
+ if (diskCacheResult == QRhiGles2::DiskCacheError)
+ return false;
+
+ const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
+
QShaderDescription vsDesc;
QShaderDescription fsDesc;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
if (isVertex) {
- if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
+ if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
+ vsDesc = shaderStage.shader().description();
} else if (isFragment) {
- if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
+ if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
+ fsDesc = shaderStage.shader().description();
}
}
@@ -3566,9 +3648,12 @@ bool QGles2GraphicsPipeline::build()
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
}
- if (!rhiD->linkProgram(program))
+ if (needsCompile && !rhiD->linkProgram(program))
return false;
+ if (needsCompile)
+ rhiD->trySaveToDiskCache(program, diskCacheKey);
+
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
@@ -3629,11 +3714,24 @@ bool QGles2ComputePipeline::build()
program = rhiD->f->glCreateProgram();
QShaderDescription csDesc;
- if (!rhiD->compileShader(program, m_shaderStage, &csDesc, nullptr))
+ QByteArray diskCacheKey;
+ QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(&m_shaderStage, 1, program, &diskCacheKey);
+ if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
- if (!rhiD->linkProgram(program))
+
+ const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
+
+ if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
return false;
+ csDesc = m_shaderStage.shader().description();
+
+ if (needsCompile && !rhiD->linkProgram(program))
+ return false;
+
+ if (needsCompile)
+ rhiD->trySaveToDiskCache(program, diskCacheKey);
+
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())