summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache.cpp80
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache_p.h43
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp130
-rw-r--r--src/gui/rhi/qrhigles2.cpp124
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h14
5 files changed, 271 insertions, 120 deletions
diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp
index 1495471457..72bdacf43f 100644
--- a/src/gui/opengl/qopenglprogrambinarycache.cpp
+++ b/src/gui/opengl/qopenglprogrambinarycache.cpp
@@ -44,6 +44,7 @@
#include <QStandardPaths>
#include <QDir>
#include <QSaveFile>
+#include <QCoreApplication>
#include <QLoggingCategory>
#include <QCryptographicHash>
@@ -54,7 +55,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
+Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
#ifndef GL_CONTEXT_LOST
#define GL_CONTEXT_LOST 0x0507
@@ -64,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#endif
+#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#endif
+
const quint32 BINSHADER_MAGIC = 0x5174;
const quint32 BINSHADER_VERSION = 0x3;
const quint32 BINSHADER_QTVERSION = QT_VERSION;
@@ -123,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
}
- qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
+ qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
@@ -154,24 +159,24 @@ static inline QByteArray readStr(const uchar **p)
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
{
if (buf.size() < BASE_HEADER_SIZE) {
- qCDebug(DBG_SHADER_CACHE, "Cached size too small");
+ qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
return false;
}
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
if (readUInt(&p) != BINSHADER_MAGIC) {
- qCDebug(DBG_SHADER_CACHE, "Magic does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
return false;
}
if (readUInt(&p) != BINSHADER_VERSION) {
- qCDebug(DBG_SHADER_CACHE, "Version does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
return false;
}
if (readUInt(&p) != BINSHADER_QTVERSION) {
- qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
return false;
}
if (readUInt(&p) != sizeof(quintptr)) {
- qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
return false;
}
return true;
@@ -196,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLenum err = funcs->glGetError();
if (err != GL_NO_ERROR) {
- qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return false;
@@ -204,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLint linkStatus = 0;
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
- qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
programId, blobSize, blobFormat, linkStatus, err);
return false;
}
- qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return true;
}
@@ -318,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
if (vendor != info.glvendor) {
// readStr returns non-null terminated strings just pointing to inside
// 'p' so must print these via the stream qCDebug and not constData().
- qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_VENDOR does not match" << vendor << info.glvendor;
undertaker.setActive();
return false;
}
QByteArray renderer = readStr(&p);
if (renderer != info.glrenderer) {
- qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_RENDERER does not match" << renderer << info.glrenderer;
undertaker.setActive();
return false;
}
QByteArray version = readStr(&p);
if (version != info.glversion) {
- qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_VERSION does not match" << version << info.glversion;
undertaker.setActive();
return false;
}
@@ -383,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
const int totalSize = headerSize + paddingSize + blobSize;
- qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
if (!blobSize)
return;
@@ -417,7 +422,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
#endif
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
if (blobSize != outSize) {
- qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
+ qCDebug(lcOpenGLProgramDiskCache, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
return;
}
@@ -433,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(blob) < blob.length())
#endif
- qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
+ qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
} else {
- qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
+ qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
}
}
@@ -452,4 +457,45 @@ void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *conte
}
#endif
+QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
+ : QOpenGLSharedResource(context->shareGroup()),
+ m_supported(false)
+{
+ if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via app attribute");
+ return;
+ }
+ if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via env var");
+ return;
+ }
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (ctx) {
+ if (ctx->isOpenGLES()) {
+ qCDebug(lcOpenGLProgramDiskCache, "OpenGL ES v%d context", ctx->format().majorVersion());
+ if (ctx->format().majorVersion() >= 3) {
+ m_supported = true;
+ } else {
+ const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
+ qCDebug(lcOpenGLProgramDiskCache, "GL_OES_get_program_binary support = %d", hasExt);
+ if (hasExt)
+ m_supported = true;
+ }
+ } else {
+ const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
+ qCDebug(lcOpenGLProgramDiskCache, "GL_ARB_get_program_binary support = %d", hasExt);
+ if (hasExt)
+ m_supported = true;
+ }
+ if (m_supported) {
+ GLint fmtCount = 0;
+ ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
+ qCDebug(lcOpenGLProgramDiskCache, "Supported binary format count = %d", fmtCount);
+ m_supported = fmtCount > 0;
+ }
+ }
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache supported = %d", m_supported);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h
index fb01e61872..f1cf24cd87 100644
--- a/src/gui/opengl/qopenglprogrambinarycache_p.h
+++ b/src/gui/opengl/qopenglprogrambinarycache_p.h
@@ -52,21 +52,26 @@
//
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qopenglshaderprogram.h>
#include <QtCore/qcache.h>
#include <QtCore/qmutex.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/private/qshader_p.h>
QT_BEGIN_NAMESPACE
+// These classes are also used by the OpenGL backend of QRhi. They must
+// therefore stay independent from QOpenGLShader(Program). Must rely only on
+// QOpenGLContext/Functions.
+
class QOpenGLProgramBinaryCache
{
public:
struct ShaderDesc {
ShaderDesc() { }
- ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
- : type(type), source(source)
+ ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
+ : stage(stage), source(source)
{ }
- QOpenGLShader::ShaderType type;
+ QShader::Stage stage;
QByteArray source;
};
struct ProgramDesc {
@@ -104,6 +109,36 @@ private:
QMutex m_mutex;
};
+// While unlikely, one application can in theory use contexts with different versions
+// or profiles. Therefore any version- or extension-specific checks must be done on a
+// per-context basis, not just once per process. QOpenGLSharedResource enables this,
+// although it's once-per-sharing-context-group, not per-context. Still, this should
+// be good enough in practice.
+class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
+{
+public:
+ QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
+ void invalidateResource() override { }
+ void freeResource(QOpenGLContext *) override { }
+
+ bool isSupported() const { return m_supported; }
+
+private:
+ bool m_supported;
+};
+
+class QOpenGLProgramBinarySupportCheckWrapper
+{
+public:
+ QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
+ {
+ return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
+ }
+
+private:
+ QOpenGLMultiGroupSharedResource m_resource;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 153a5dd9ee..4986ca573d 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -47,7 +47,6 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qcoreapplication.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
@@ -178,7 +177,7 @@ QT_BEGIN_NAMESPACE
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
-Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
+Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
// For GLES 3.1/3.2
#ifndef GL_GEOMETRY_SHADER
@@ -209,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#endif
-#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
-#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
-#endif
-
#ifndef QT_OPENGL_ES_2
static inline bool isFormatGLES(const QSurfaceFormat &f)
{
@@ -1080,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
return addCacheableShaderFromSourceCode(type, QByteArray(source));
}
+static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
+{
+ switch (type) {
+ case QOpenGLShader::Vertex:
+ return QShader::VertexStage;
+ case QOpenGLShader::Fragment:
+ return QShader::FragmentStage;
+ case QOpenGLShader::Geometry:
+ return QShader::GeometryStage;
+ case QOpenGLShader::TessellationControl:
+ return QShader::TessellationControlStage;
+ case QOpenGLShader::TessellationEvaluation:
+ return QShader::TessellationEvaluationStage;
+ case QOpenGLShader::Compute:
+ return QShader::ComputeStage;
+ }
+ return QShader::VertexStage;
+}
+
+static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
+{
+ switch (stage) {
+ case QShader::VertexStage:
+ return QOpenGLShader::Vertex;
+ case QShader::TessellationControlStage:
+ return QOpenGLShader::TessellationControl;
+ case QShader::TessellationEvaluationStage:
+ return QOpenGLShader::TessellationEvaluation;
+ case QShader::GeometryStage:
+ return QOpenGLShader::Geometry;
+ case QShader::FragmentStage:
+ return QOpenGLShader::Fragment;
+ case QShader::ComputeStage:
+ return QOpenGLShader::Compute;
+ }
+ return QOpenGLShader::Vertex;
+}
+
/*!
\overload
@@ -1108,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
- d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
+ d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
return true;
}
@@ -1165,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceFile(type, fileName);
- QOpenGLProgramBinaryCache::ShaderDesc shader(type);
+ QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
// NB! It could be tempting to defer reading the file contents and just
// hash the filename as the cache key, perhaps combined with last-modified
// timestamp checks. However, this would raise a number of issues (no
@@ -3719,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
return true;
}
-// While unlikely, one application can in theory use contexts with different versions
-// or profiles. Therefore any version- or extension-specific checks must be done on a
-// per-context basis, not just once per process. QOpenGLSharedResource enables this,
-// although it's once-per-sharing-context-group, not per-context. Still, this should
-// be good enough in practice.
-class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
-{
-public:
- QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
- void invalidateResource() override { }
- void freeResource(QOpenGLContext *) override { }
-
- bool isSupported() const { return m_supported; }
-
-private:
- bool m_supported;
-};
-
-QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
- : QOpenGLSharedResource(context->shareGroup()),
- m_supported(false)
-{
- if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
- qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
- return;
- }
- if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
- qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
- return;
- }
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (ctx) {
- if (ctx->isOpenGLES()) {
- qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
- if (ctx->format().majorVersion() >= 3) {
- m_supported = true;
- } else {
- const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
- qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt);
- if (hasExt)
- m_supported = true;
- }
- } else {
- const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
- qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
- if (hasExt)
- m_supported = true;
- }
- if (m_supported) {
- GLint fmtCount = 0;
- ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
- qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
- m_supported = fmtCount > 0;
- }
- }
- qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
-}
-
-class QOpenGLProgramBinarySupportCheckWrapper
-{
-public:
- QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
- {
- return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
- }
-
-private:
- QOpenGLMultiGroupSharedResource m_resource;
-};
-
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
@@ -3800,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
{
Q_Q(QOpenGLShaderProgram);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
- QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
+ QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
if (!s->compileSourceCode(shader.source)) {
log = s->log();
return false;
@@ -3819,19 +3781,19 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
Q_Q(QOpenGLShaderProgram);
const QByteArray cacheKey = binaryProgram.cacheKey();
- if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
- qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
+ if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
+ qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
binaryProgram.shaders.count(), cacheKey.constData());
bool needsCompile = true;
if (binCache.load(cacheKey, q->programId())) {
- qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
needsCompile = false;
}
bool needsSave = false;
if (needsCompile) {
- qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
if (compileCacheable())
needsSave = true;
else
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())
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index e7bcb626b6..646836a699 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -692,13 +692,23 @@ public:
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
int effectiveSampleCount(int sampleCount) const;
- bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
- QShaderDescription *desc, int *glslVersionUsed);
+ QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
+ bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program);
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst);
+ bool isProgramBinaryDiskCacheEnabled() const;
+
+ enum DiskCacheResult {
+ DiskCacheHit,
+ DiskCacheMiss,
+ DiskCacheError
+ };
+ DiskCacheResult tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
+ GLuint program, QByteArray *cacheKey);
+ void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
QOpenGLContext *ctx = nullptr;
bool importedContext = false;