diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-10-01 01:01:20 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-10-01 11:47:42 +0200 |
commit | 8791a8398ac232a8daab98601f1bef88bdf7638f (patch) | |
tree | 4be3c8daaff311943215f399ae7300ca4af4f969 /src/gui | |
parent | 56f084781e2b8891929eca0070212fd7a32b32fc (diff) | |
parent | 4e40c54a3caabb6bced27e18e040ee88b739a3c8 (diff) |
Merge "Merge remote-tracking branch 'origin/5.14' into 5.15"
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/opengl/qopenglprogrambinarycache.cpp | 80 | ||||
-rw-r--r-- | src/gui/opengl/qopenglprogrambinarycache_p.h | 43 | ||||
-rw-r--r-- | src/gui/opengl/qopenglshaderprogram.cpp | 130 | ||||
-rw-r--r-- | src/gui/rhi/cs_tdr_p.h (renamed from src/gui/rhi/cs_tdr.h) | 18 | ||||
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 246 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 101 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p_p.h | 67 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 23 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11_p_p.h | 4 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 149 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 14 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 93 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal_p_p.h | 4 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 56 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p_p.h | 4 | ||||
-rw-r--r-- | src/gui/text/qfont.cpp | 11 |
16 files changed, 592 insertions, 451 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/cs_tdr.h b/src/gui/rhi/cs_tdr_p.h index f80cb3a498..620a4a101d 100644 --- a/src/gui/rhi/cs_tdr.h +++ b/src/gui/rhi/cs_tdr_p.h @@ -34,7 +34,21 @@ ** ****************************************************************************/ -#include <qglobal.h> +#ifndef CS_TDR_P_H +#define CS_TDR_P_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 <QtCore/qglobal.h> #ifdef Q_OS_WIN @@ -207,3 +221,5 @@ const BYTE g_killDeviceByTimingOut[] = }; #endif // Q_OS_WIN + +#endif // CS_TDR_P_H diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index ee4caa47a0..08bafebdec 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -1981,6 +1981,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const How the renderbuffer is implemented by a backend is not exposed to the applications. In some cases it may be backed by ordinary textures, while in others there may be a different kind of native resource used. + + Renderbuffers that are used as (and are only used as) depth-stencil buffers + in combination with a QRhiSwapChain's color buffers should have the + UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers, + depending on the backend and the underlying APIs, be more efficient, and + QRhi provides automatic sizing behavior to match the color buffers, which + means calling setPixelSize() and build() are not necessary for such + renderbuffers. */ /*! @@ -1996,12 +2004,15 @@ QRhiResource::Type QRhiBuffer::resourceType() const Flag values for flags() and setFlags() \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates - that the renderbuffer is only used in combination with a QRhiSwapChain and - never in other ways. Relevant with some backends, while others ignore it. - With OpenGL where a separate windowing system interface API is in use (EGL, - GLX, etc.), the flag is important since it avoids creating any actual - resource as there is already a windowing system provided depth/stencil - buffer as requested by QSurfaceFormat. + that the renderbuffer is only used in combination with a QRhiSwapChain, and + never in any other way. This provides automatic sizing and resource + rebuilding, so calling setPixelSize() or build() is not needed whenever + this flag is set. This flag value may also trigger backend-specific + behavior, for example with OpenGL, where a separate windowing system + interface API is in use (EGL, GLX, etc.), the flag is especially important + as it avoids creating any actual renderbuffer resource as there is already + a windowing system provided depth/stencil buffer as requested by + QSurfaceFormat. */ /*! @@ -2523,16 +2534,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const be used with the same pipeline, assuming the pipeline was built with one of them in the first place. - Creating and then using a new \c srb2 that is very similar to \c srb with - the exception of referencing another texture could be implemented like the - following: - \badcode srb2 = rhi->newShaderResourceBindings(); - QVector<QRhiShaderResourceBinding> bindings = srb->bindings(); - bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler); - srb2->setBindings(bindings); - srb2->build(); ... cb->setGraphicsPipeline(ps); cb->setShaderResources(srb2); // binds srb2 @@ -2634,43 +2637,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind \internal */ QRhiShaderResourceBinding::QRhiShaderResourceBinding() - : d(new QRhiShaderResourceBindingPrivate) -{ -} - -/*! - \internal - */ -void QRhiShaderResourceBinding::detach() { - qAtomicDetach(d); -} - -/*! - \internal - */ -QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other) - : d(other.d) -{ - d->ref.ref(); -} - -/*! - \internal - */ -QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other) -{ - qAtomicAssign(d, other.d); - return *this; -} - -/*! - Destructor. - */ -QRhiShaderResourceBinding::~QRhiShaderResourceBinding() -{ - if (!d->ref.deref()) - delete d; + // Zero out everything, including possible padding, because will use + // qHashBits on it. + memset(&d.u, 0, sizeof(d.u)); } /*! @@ -2687,8 +2657,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding() */ bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const { - return (d == other.d) - || (d->binding == other.d->binding && d->stage == other.d->stage && d->type == other.d->type); + return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type; } /*! @@ -2701,15 +2670,13 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( int binding, StageFlags stage, QRhiBuffer *buf) { QRhiShaderResourceBinding b; - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.loadRelaxed() == 1); - d->binding = binding; - d->stage = stage; - d->type = UniformBuffer; - d->u.ubuf.buf = buf; - d->u.ubuf.offset = 0; - d->u.ubuf.maybeSize = 0; // entire buffer - d->u.ubuf.hasDynamicOffset = false; + b.d.binding = binding; + b.d.stage = stage; + b.d.type = UniformBuffer; + b.d.u.ubuf.buf = buf; + b.d.u.ubuf.offset = 0; + b.d.u.ubuf.maybeSize = 0; // entire buffer + b.d.u.ubuf.hasDynamicOffset = false; return b; } @@ -2730,9 +2697,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( { Q_ASSERT(size > 0); QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->u.ubuf.offset = offset; - d->u.ubuf.maybeSize = size; + b.d.u.ubuf.offset = offset; + b.d.u.ubuf.maybeSize = size; return b; } @@ -2751,8 +2717,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff int binding, StageFlags stage, QRhiBuffer *buf, int size) { QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->u.ubuf.hasDynamicOffset = true; + b.d.u.ubuf.hasDynamicOffset = true; return b; } @@ -2765,13 +2730,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler) { QRhiShaderResourceBinding b; - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.loadRelaxed() == 1); - d->binding = binding; - d->stage = stage; - d->type = SampledTexture; - d->u.stex.tex = tex; - d->u.stex.sampler = sampler; + b.d.binding = binding; + b.d.stage = stage; + b.d.type = SampledTexture; + b.d.u.stex.tex = tex; + b.d.u.stex.sampler = sampler; return b; } @@ -2787,13 +2750,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad( int binding, StageFlags stage, QRhiTexture *tex, int level) { QRhiShaderResourceBinding b; - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.loadRelaxed() == 1); - d->binding = binding; - d->stage = stage; - d->type = ImageLoad; - d->u.simage.tex = tex; - d->u.simage.level = level; + b.d.binding = binding; + b.d.stage = stage; + b.d.type = ImageLoad; + b.d.u.simage.tex = tex; + b.d.u.simage.level = level; return b; } @@ -2809,8 +2770,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore( int binding, StageFlags stage, QRhiTexture *tex, int level) { QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->type = ImageStore; + b.d.type = ImageStore; return b; } @@ -2826,8 +2786,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore( int binding, StageFlags stage, QRhiTexture *tex, int level) { QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->type = ImageLoadStore; + b.d.type = ImageLoadStore; return b; } @@ -2841,14 +2800,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( int binding, StageFlags stage, QRhiBuffer *buf) { QRhiShaderResourceBinding b; - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.loadRelaxed() == 1); - d->binding = binding; - d->stage = stage; - d->type = BufferLoad; - d->u.sbuf.buf = buf; - d->u.sbuf.offset = 0; - d->u.sbuf.maybeSize = 0; // entire buffer + b.d.binding = binding; + b.d.stage = stage; + b.d.type = BufferLoad; + b.d.u.sbuf.buf = buf; + b.d.u.sbuf.offset = 0; + b.d.u.sbuf.maybeSize = 0; // entire buffer return b; } @@ -2864,9 +2821,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( { Q_ASSERT(size > 0); QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->u.sbuf.offset = offset; - d->u.sbuf.maybeSize = size; + b.d.u.sbuf.offset = offset; + b.d.u.sbuf.maybeSize = size; return b; } @@ -2880,8 +2836,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( int binding, StageFlags stage, QRhiBuffer *buf) { QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->type = BufferStore; + b.d.type = BufferStore; return b; } @@ -2897,9 +2852,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( { Q_ASSERT(size > 0); QRhiShaderResourceBinding b = bufferStore(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->u.sbuf.offset = offset; - d->u.sbuf.maybeSize = size; + b.d.u.sbuf.offset = offset; + b.d.u.sbuf.maybeSize = size; return b; } @@ -2913,8 +2867,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( int binding, StageFlags stage, QRhiBuffer *buf) { QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->type = BufferLoadStore; + b.d.type = BufferLoadStore; return b; } @@ -2930,9 +2883,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( { Q_ASSERT(size > 0); QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf); - QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - d->u.sbuf.offset = offset; - d->u.sbuf.maybeSize = size; + b.d.u.sbuf.offset = offset; + b.d.u.sbuf.maybeSize = size; return b; } @@ -2948,28 +2900,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( */ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW { - if (a.d == b.d) + const QRhiShaderResourceBinding::Data *da = a.data(); + const QRhiShaderResourceBinding::Data *db = b.data(); + + if (da == db) return true; - if (a.d->binding != b.d->binding - || a.d->stage != b.d->stage - || a.d->type != b.d->type) + + if (da->binding != db->binding + || da->stage != db->stage + || da->type != db->type) { return false; } - switch (a.d->type) { + switch (da->type) { case QRhiShaderResourceBinding::UniformBuffer: - if (a.d->u.ubuf.buf != b.d->u.ubuf.buf - || a.d->u.ubuf.offset != b.d->u.ubuf.offset - || a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize) + if (da->u.ubuf.buf != db->u.ubuf.buf + || da->u.ubuf.offset != db->u.ubuf.offset + || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize) { return false; } break; case QRhiShaderResourceBinding::SampledTexture: - if (a.d->u.stex.tex != b.d->u.stex.tex - || a.d->u.stex.sampler != b.d->u.stex.sampler) + if (da->u.stex.tex != db->u.stex.tex + || da->u.stex.sampler != db->u.stex.sampler) { return false; } @@ -2979,8 +2935,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind case QRhiShaderResourceBinding::ImageStore: Q_FALLTHROUGH(); case QRhiShaderResourceBinding::ImageLoadStore: - if (a.d->u.simage.tex != b.d->u.simage.tex - || a.d->u.simage.level != b.d->u.simage.level) + if (da->u.simage.tex != db->u.simage.tex + || da->u.simage.level != db->u.simage.level) { return false; } @@ -2990,9 +2946,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind case QRhiShaderResourceBinding::BufferStore: Q_FALLTHROUGH(); case QRhiShaderResourceBinding::BufferLoadStore: - if (a.d->u.sbuf.buf != b.d->u.sbuf.buf - || a.d->u.sbuf.offset != b.d->u.sbuf.offset - || a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize) + if (da->u.sbuf.buf != db->u.sbuf.buf + || da->u.sbuf.offset != db->u.sbuf.offset + || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize) { return false; } @@ -3023,16 +2979,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind */ uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW { - const char *u = reinterpret_cast<const char *>(&b.d->u); - return seed + uint(b.d->binding) + 10 * uint(b.d->stage) + 100 * uint(b.d->type) - + qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed); + const QRhiShaderResourceBinding::Data *d = b.data(); + return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type) + + qHashBits(&d->u, sizeof(d->u), seed); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) { - const QRhiShaderResourceBindingPrivate *d = b.d; QDebugStateSaver saver(dbg); + const QRhiShaderResourceBinding::Data *d = b.data(); dbg.nospace() << "QRhiShaderResourceBinding(" << "binding=" << d->binding << " stage=" << d->stage @@ -3100,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) #endif #ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QVarLengthArray<QRhiShaderResourceBinding, 8> &bindings) +{ + return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings); +} + QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) { QDebugStateSaver saver(dbg); @@ -3351,7 +3312,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const { sc = rhi->newSwapChain(); ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, - QSize(), // no need to set the size yet + QSize(), // no need to set the size here due to UsedWithSwapChainOnly 1, QRhiRenderBuffer::UsedWithSwapChainOnly); sc->setWindow(window); @@ -3363,9 +3324,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const void resizeSwapChain() { - const QSize outputSize = sc->surfacePixelSize(); - ds->setPixelSize(outputSize); - ds->build(); hasSwapChain = sc->buildOrResize(); } @@ -3559,10 +3517,24 @@ QRhiResource::Type QRhiSwapChain::resourceType() const \return The size of the window's associated surface or layer. Do not assume this is the same as QWindow::size() * QWindow::devicePixelRatio(). - Can be called before buildOrResize() (but with window() already set), which - allows setting the correct size for the depth-stencil buffer that is then - used together with the swapchain's color buffers. Also used in combination - with currentPixelSize() to detect size changes. + \note Can also be called before buildOrResize(), if at least window() is + already set) This in combination with currentPixelSize() allows to detect + when a swapchain needs to be resized. However, watch out for the fact that + the size of the underlying native object (surface, layer, or similar) is + "live", so whenever this function is called, it returns the latest value + reported by the underlying implementation, without any atomicity guarantee. + Therefore, using this function to determine pixel sizes for graphics + resources that are used in a frame is strongly discouraged. Rely on + currentPixelSize() instead which returns a size that is atomic and will not + change between buildOrResize() invocations. + + \note For depth-stencil buffers used in combination with the swapchain's + color buffers, it is strongly recommended to rely on the automatic sizing + and rebuilding behavior provided by the + QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface + size via this function just to get a size that can be passed to + QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of + atomicity as described above. \sa currentPixelSize() */ @@ -5541,7 +5513,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state) { - auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; }); + auto it = m_buffers.find(buf); if (it != m_buffers.end()) { if (it->access != *access) { const QByteArray name = buf->name(); @@ -5557,12 +5529,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc } Buffer b; - b.buf = buf; b.slot = slot; b.access = *access; b.stage = *stage; b.stateAtPassBegin = state; // first use -> initial state - m_buffers.append(b); + m_buffers.insert(buf, b); } static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, @@ -5581,7 +5552,7 @@ static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess acces void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state) { - auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; }); + auto it = m_textures.find(tex); if (it != m_textures.end()) { if (it->access != *access) { // Different subresources of a texture may be used for both load @@ -5605,11 +5576,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a } Texture t; - t.tex = tex; t.access = *access; t.stage = *stage; t.stateAtPassBegin = state; // first use -> initial state - m_textures.append(t); + m_textures.insert(tex, t); } QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages) diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index c73f03cf72..f8f922cfdb 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -52,6 +52,7 @@ #include <QSize> #include <QMatrix4x4> #include <QVector> +#include <QVarLengthArray> #include <QThread> #include <QColor> #include <QImage> @@ -320,10 +321,6 @@ public: Q_DECLARE_FLAGS(StageFlags, StageFlag) QRhiShaderResourceBinding(); - QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other); - QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other); - ~QRhiShaderResourceBinding(); - void detach(); bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const; @@ -344,19 +341,49 @@ public: static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf); static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size); + struct Data + { + int binding; + QRhiShaderResourceBinding::StageFlags stage; + QRhiShaderResourceBinding::Type type; + struct UniformBufferData { + QRhiBuffer *buf; + int offset; + int maybeSize; + bool hasDynamicOffset; + }; + struct SampledTextureData { + QRhiTexture *tex; + QRhiSampler *sampler; + }; + struct StorageImageData { + QRhiTexture *tex; + int level; + }; + struct StorageBufferData { + QRhiBuffer *buf; + int offset; + int maybeSize; + }; + union { + UniformBufferData ubuf; + SampledTextureData stex; + StorageImageData simage; + StorageBufferData sbuf; + } u; + }; + + Data *data() { return &d; } + const Data *data() const { return &d; } + private: - QRhiShaderResourceBindingPrivate *d; - friend class QRhiShaderResourceBindingPrivate; - friend Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW; - friend Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW; - friend Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW; -#ifndef QT_NO_DEBUG_STREAM - friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &); -#endif + Data d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags) +Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_MOVABLE_TYPE); + Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW; Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW; Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW; @@ -900,8 +927,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource public: QRhiResource::Type resourceType() const override; - QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; } - void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; } + void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; } + + template<typename InputIterator> + void setBindings(InputIterator first, InputIterator last) + { + m_bindings.clear(); + std::copy(first, last, std::back_inserter(m_bindings)); + } + + void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed + { + setBindings(bindings.cbegin(), bindings.cend()); + } + + const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); } + const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); } bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const; @@ -909,7 +950,7 @@ public: protected: QRhiShaderResourceBindings(QRhiImplementation *rhi); - QVector<QRhiShaderResourceBinding> m_bindings; + QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings; #ifndef QT_NO_DEBUG_STREAM friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &); #endif @@ -1040,8 +1081,15 @@ public: FrontFace frontFace() const { return m_frontFace; } void setFrontFace(FrontFace f) { m_frontFace = f; } - QVector<TargetBlend> targetBlends() const { return m_targetBlends; } - void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; } + void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; } + template<typename InputIterator> + void setTargetBlends(InputIterator first, InputIterator last) + { + m_targetBlends.clear(); + std::copy(first, last, std::back_inserter(m_targetBlends)); + } + const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); } + const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); } bool hasDepthTest() const { return m_depthTest; } void setDepthTest(bool enable) { m_depthTest = enable; } @@ -1073,8 +1121,19 @@ public: float lineWidth() const { return m_lineWidth; } void setLineWidth(float width) { m_lineWidth = width; } - QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; } - void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; } + void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; } + template<typename InputIterator> + void setShaderStages(InputIterator first, InputIterator last) + { + m_shaderStages.clear(); + std::copy(first, last, std::back_inserter(m_shaderStages)); + } + void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed + { + setShaderStages(stages.cbegin(), stages.cend()); + } + const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); } + const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); } QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; } void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; } @@ -1093,7 +1152,7 @@ protected: Topology m_topology = Triangles; CullMode m_cullMode = None; FrontFace m_frontFace = CCW; - QVector<TargetBlend> m_targetBlends; + QVarLengthArray<TargetBlend, 8> m_targetBlends; bool m_depthTest = false; bool m_depthWrite = false; CompareOp m_depthOp = Less; @@ -1104,7 +1163,7 @@ protected: quint32 m_stencilWriteMask = 0xFF; int m_sampleCount = 1; float m_lineWidth = 1.0f; - QVector<QRhiShaderStage> m_shaderStages; + QVarLengthArray<QRhiShaderStage, 4> m_shaderStages; QRhiVertexInputLayout m_vertexInputLayout; QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr; QRhiRenderPassDescriptor *m_renderPassDesc = nullptr; diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index be2808549c..822da528f1 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -381,57 +381,6 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE); -class Q_GUI_EXPORT QRhiShaderResourceBindingPrivate -{ -public: - QRhiShaderResourceBindingPrivate() - : ref(1) - { - } - - QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other) - : ref(1), - binding(other->binding), - stage(other->stage), - type(other->type), - u(other->u) - { - } - - static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; } - static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; } - - QAtomicInt ref; - int binding; - QRhiShaderResourceBinding::StageFlags stage; - QRhiShaderResourceBinding::Type type; - struct UniformBufferData { - QRhiBuffer *buf; - int offset; - int maybeSize; - bool hasDynamicOffset; - }; - struct SampledTextureData { - QRhiTexture *tex; - QRhiSampler *sampler; - }; - struct StorageImageData { - QRhiTexture *tex; - int level; - }; - struct StorageBufferData { - QRhiBuffer *buf; - int offset; - int maybeSize; - }; - union { - UniformBufferData ubuf; - SampledTextureData stex; - StorageImageData simage; - StorageBufferData sbuf; - } u; -}; - template<typename T> struct QRhiBatchedBindings { @@ -554,28 +503,32 @@ public: const UsageState &state); struct Buffer { - QRhiBuffer *buf; int slot; BufferAccess access; BufferStage stage; UsageState stateAtPassBegin; }; - const QVector<Buffer> *buffers() const { return &m_buffers; } + + using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator; + BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); } + BufferIterator cendBuffers() const { return m_buffers.cend(); } struct Texture { - QRhiTexture *tex; TextureAccess access; TextureStage stage; UsageState stateAtPassBegin; }; - const QVector<Texture> *textures() const { return &m_textures; } + + using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator; + TextureIterator cbeginTextures() const { return m_textures.cbegin(); } + TextureIterator cendTextures() const { return m_textures.cend(); } static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages); static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages); private: - QVector<Buffer> m_buffers; - QVector<Texture> m_textures; + QHash<QRhiBuffer *, Buffer> m_buffers; + QHash<QRhiTexture *, Texture> m_textures; }; Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 1d2f3cfa80..b82a68f3dd 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -36,7 +36,7 @@ #include "qrhid3d11_p_p.h" #include "qshader_p.h" -#include "cs_tdr.h" +#include "cs_tdr_p.h" #include <QWindow> #include <QOperatingSystemVersion> #include <qmath.h> @@ -598,7 +598,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind bool hasDynamicOffsetInSrb = false; bool srbUpdate = false; for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -1746,7 +1746,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.clear(); for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -3082,11 +3082,11 @@ bool QD3D11ShaderResourceBindings::build() if (!sortedBindings.isEmpty()) release(); - sortedBindings = m_bindings; + std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings)); std::sort(sortedBindings.begin(), sortedBindings.end(), [](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) { - return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding; + return a.data()->binding < b.data()->binding; }); boundResourceData.resize(sortedBindings.count()); @@ -3939,9 +3939,16 @@ bool QD3D11SwapChain::buildOrResize() m_depthStencil->sampleCount(), m_sampleCount); } if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) { - qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.", - m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), - pixelSize.width(), pixelSize.height()); + if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) { + m_depthStencil->setPixelSize(pixelSize); + if (!m_depthStencil->build()) + qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d", + pixelSize.width(), pixelSize.height()); + } else { + qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.", + m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), + pixelSize.width(), pixelSize.height()); + } } currentFrameSlot = 0; diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index cf4808510c..6699e7ad64 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings void release() override; bool build() override; - QVector<QRhiShaderResourceBinding> sortedBindings; + QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings; uint generation = 0; // Keep track of the generation number of each referenced QRhi* to be able @@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings BoundStorageBufferData sbuf; }; }; - QVector<BoundResourceData> boundResourceData; + QVarLengthArray<BoundResourceData, 8> boundResourceData; QRhiBatchedBindings<ID3D11Buffer *> vsubufs; QRhiBatchedBindings<UINT> vsubufoffsets; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index cc5d41ea46..190385d5de 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. @@ -583,7 +586,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag int QRhiGles2::ubufAlignment() const { - return 256; + // No real uniform buffers are used so no need to pretend there is any + // alignment requirement. + return 1; } bool QRhiGles2::isYUpInFramebuffer() const @@ -863,7 +868,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb); bool hasDynamicOffsetInSrb = false; for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data(); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: // no BufUniformRead / AccessUniform because no real uniform buffers are used @@ -2181,7 +2186,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) { GLbitfield barriers = 0; QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]); - const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers(); // we only care about after-write, not any other accesses, and // cannot tell if something was written in a shader several passes // ago: now the previously written resource may be used with an @@ -2189,17 +2193,16 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) // barrier in theory. Hence setting all barrier bits whenever // something previously written is used for the first time in a // subsequent pass. - for (const QRhiPassResourceTracker::Buffer &b : *buffers) { - QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access); + for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) { + QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access); if (accessBeforePass == QGles2Buffer::AccessStorageWrite || accessBeforePass == QGles2Buffer::AccessStorageReadWrite) { barriers |= GL_ALL_BARRIER_BITS; } } - const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures(); - for (const QRhiPassResourceTracker::Texture &t : *textures) { - QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access); + for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) { + QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access); if (accessBeforePass == QGles2Texture::AccessStorageWrite || accessBeforePass == QGles2Texture::AccessStorageReadWrite) { @@ -2301,7 +2304,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC int texUnit = 0; for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data(); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -2707,8 +2710,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; @@ -2727,8 +2729,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; } } @@ -2757,8 +2759,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; } } @@ -2766,8 +2768,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); @@ -2804,7 +2813,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage f->glAttachShader(program, shader); - *desc = bakedShader.description(); return true; } @@ -2859,6 +2867,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) { @@ -3545,17 +3615,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(); } } @@ -3564,9 +3646,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); @@ -3627,11 +3712,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()) @@ -3705,6 +3803,13 @@ bool QGles2SwapChain::buildOrResize() m_currentPixelSize = surfacePixelSize(); pixelSize = m_currentPixelSize; + if (m_depthStencil && m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly) + && m_depthStencil->pixelSize() != pixelSize) + { + m_depthStencil->setPixelSize(pixelSize); + m_depthStencil->build(); + } + rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc); rt.d.pixelSize = pixelSize; rt.d.dpr = float(m_window->devicePixelRatio()); 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; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index d4043f00a5..4dc12f0691 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -656,7 +656,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } res[KNOWN_STAGES]; for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding); + const QRhiShaderResourceBinding::Data *b = binding.data(); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: { @@ -875,7 +875,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind // do buffer writes, figure out if we need to rebind, and mark as in-use for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -1036,44 +1036,11 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb, } } -QSize safeOutputSize(QRhiMetal *rhiD, QMetalCommandBuffer *cbD) -{ - QSize size = cbD->currentTarget->pixelSize(); - - // So now we have the issue that the texture (drawable) size may have - // changed again since swapchain buildOrResize() was called. This can - // happen for example when interactively resizing the window a lot in one - // go, and command buffer building happens on a dedicated thread (f.ex. - // using the threaded render loop of Qt Quick). - // - // This is only an issue when running in debug mode with XCode because Metal - // validation will fail when setting viewport or scissor with the real size - // being smaller than what we think it is. So query the drawable size right - // here, in debug mode at least. - // - // In addition, we have to take the smaller of the two widths and heights - // to be safe, apparently. In some cases validation seems to think that the - // "render pass width" (or height) is the old(?) value. - -#ifdef QT_DEBUG - if (cbD->currentTarget->resourceType() == QRhiResource::RenderTarget) { - Q_ASSERT(rhiD->currentSwapChain); - const QSize otherSize = rhiD->currentSwapChain->surfacePixelSize(); - size.setWidth(qMin(size.width(), otherSize.width())); - size.setHeight(qMin(size.height(), otherSize.height())); - } -#else - Q_UNUSED(rhiD); -#endif - - return size; -} - void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) { QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass); - const QSize outputSize = safeOutputSize(this, cbD); + const QSize outputSize = cbD->currentTarget->pixelSize(); // x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport float x, y, w, h; @@ -1105,7 +1072,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass); Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)); - const QSize outputSize = safeOutputSize(this, cbD); + const QSize outputSize = cbD->currentTarget->pixelSize(); // x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor int x, y, w, h; @@ -2801,21 +2768,21 @@ bool QMetalShaderResourceBindings::build() if (!sortedBindings.isEmpty()) release(); - sortedBindings = m_bindings; + std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings)); std::sort(sortedBindings.begin(), sortedBindings.end(), [](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) { - return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding; + return a.data()->binding < b.data()->binding; }); if (!sortedBindings.isEmpty()) - maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding; + maxBinding = sortedBindings.last().data()->binding; else maxBinding = -1; boundResourceData.resize(sortedBindings.count()); for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data(); QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -3529,20 +3496,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget() QSize QMetalSwapChain::surfacePixelSize() { - // may be called before build, must not access other than m_* - - NSView *v = (NSView *) m_window->winId(); - if (v) { - CAMetalLayer *layer = (CAMetalLayer *) [v layer]; - if (layer) { - CGSize size = layer.bounds.size; - size.width *= layer.contentsScale; - size.height *= layer.contentsScale; - layer.drawableSize = size; - return QSize(int(size.width), int(size.height)); - } - } - return QSize(); + Q_ASSERT(m_window); + return m_window->size() * m_window->devicePixelRatio(); } QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor() @@ -3593,8 +3548,9 @@ bool QMetalSwapChain::buildOrResize() return false; } - NSView *v = (NSView *) window->winId(); - d->layer = (CAMetalLayer *) [v layer]; + NSView *view = reinterpret_cast<NSView *>(window->winId()); + Q_ASSERT(view); + d->layer = static_cast<CAMetalLayer *>(view.layer); Q_ASSERT(d->layer); chooseFormats(); @@ -3623,7 +3579,15 @@ bool QMetalSwapChain::buildOrResize() d->layer.opaque = YES; } - m_currentPixelSize = surfacePixelSize(); + // Now set the layer's drawableSize which will stay set to the same value + // until the next buildOrResize(), thus ensuring atomicity with regards to + // the drawable size in frames. + CGSize layerSize = d->layer.bounds.size; + layerSize.width *= d->layer.contentsScale; + layerSize.height *= d->layer.contentsScale; + d->layer.drawableSize = layerSize; + + m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize(); pixelSize = m_currentPixelSize; [d->layer setDevice: rhiD->d->dev]; @@ -3644,9 +3608,16 @@ bool QMetalSwapChain::buildOrResize() m_depthStencil->sampleCount(), m_sampleCount); } if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) { - qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.", - m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), - pixelSize.width(), pixelSize.height()); + if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) { + m_depthStencil->setPixelSize(pixelSize); + if (!m_depthStencil->build()) + qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d", + pixelSize.width(), pixelSize.height()); + } else { + qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.", + m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), + pixelSize.width(), pixelSize.height()); + } } rtWrapper.d->pixelSize = pixelSize; diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 7fd7aba923..688fec8147 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings void release() override; bool build() override; - QVector<QRhiShaderResourceBinding> sortedBindings; + QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings; int maxBinding = -1; struct BoundUniformBufferData { @@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings BoundStorageBufferData sbuf; }; }; - QVector<BoundResourceData> boundResourceData; + QVarLengthArray<BoundResourceData, 8> boundResourceData; uint generation = 0; friend class QRhiMetal; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 444c91dd75..7e2e914af3 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2313,7 +2313,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) { srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count()); for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]); VkWriteDescriptorSet writeInfo; @@ -3556,12 +3556,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi if (tracker.isEmpty()) return; - const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers(); - for (const QRhiPassResourceTracker::Buffer &b : *buffers) { - QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf); - VkAccessFlags access = toVkAccess(b.access); - VkPipelineStageFlags stage = toVkPipelineStage(b.stage); - QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin); + for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) { + QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key()); + VkAccessFlags access = toVkAccess(it->access); + VkPipelineStageFlags stage = toVkPipelineStage(it->stage); + QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin); if (!s.stage) continue; if (s.access == access && s.stage == stage) { @@ -3575,7 +3574,7 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufMemBarrier.srcAccessMask = s.access; bufMemBarrier.dstAccessMask = access; - bufMemBarrier.buffer = bufD->buffers[b.slot]; + bufMemBarrier.buffer = bufD->buffers[it->slot]; bufMemBarrier.size = VK_WHOLE_SIZE; df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0, 0, nullptr, @@ -3583,13 +3582,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi 0, nullptr); } - const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures(); - for (const QRhiPassResourceTracker::Texture &t : *textures) { - QVkTexture *texD = QRHI_RES(QVkTexture, t.tex); - VkImageLayout layout = toVkLayout(t.access); - VkAccessFlags access = toVkAccess(t.access); - VkPipelineStageFlags stage = toVkPipelineStage(t.stage); - QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin); + for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) { + QVkTexture *texD = QRHI_RES(QVkTexture, it.key()); + VkImageLayout layout = toVkLayout(it->access); + VkAccessFlags access = toVkAccess(it->access); + VkPipelineStageFlags stage = toVkPipelineStage(it->stage); + QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin); if (s.access == access && s.stage == stage && s.layout == layout) { if (!accessIsWrite(access)) continue; @@ -3870,7 +3868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin bool hasDynamicOffsetInSrb = false; for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding); + const QRhiShaderResourceBinding::Data *b = binding.data(); switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic) @@ -3889,7 +3887,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin // Do host writes and mark referenced shader resources as in-use. // Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects. for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); + const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]); QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]); switch (b->type) { @@ -4022,7 +4020,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin // and neither srb nor dynamicOffsets has any such ordering // requirement. for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding); + const QRhiShaderResourceBinding::Data *b = binding.data(); if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) { uint32_t offset = 0; for (int i = 0; i < dynamicOffsetCount; ++i) { @@ -4750,7 +4748,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic dst->compareOp = toVkCompareOp(src.compareOp); } -static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b) +static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b) { switch (b->type) { case QRhiShaderResourceBinding::UniformBuffer: @@ -5697,16 +5695,17 @@ bool QVkShaderResourceBindings::build() for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) descSets[i] = VK_NULL_HANDLE; - sortedBindings = m_bindings; + sortedBindings.clear(); + std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings)); std::sort(sortedBindings.begin(), sortedBindings.end(), [](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) { - return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding; + return a.data()->binding < b.data()->binding; }); QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings; for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) { - const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding); + const QRhiShaderResourceBinding::Data *b = binding.data(); VkDescriptorSetLayoutBinding vkbinding; memset(&vkbinding, 0, sizeof(vkbinding)); vkbinding.binding = uint32_t(b->binding); @@ -6315,9 +6314,16 @@ bool QVkSwapChain::buildOrResize() m_depthStencil->sampleCount(), m_sampleCount); } if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) { - qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.", - m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), - pixelSize.width(), pixelSize.height()); + if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) { + m_depthStencil->setPixelSize(pixelSize); + if (!m_depthStencil->build()) + qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d", + pixelSize.width(), pixelSize.height()); + } else { + qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.", + m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(), + pixelSize.width(), pixelSize.height()); + } } if (!m_renderPassDesc) diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index a390bc3707..d83a338acd 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings void release() override; bool build() override; - QVector<QRhiShaderResourceBinding> sortedBindings; + QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings; int poolIndex = -1; VkDescriptorSetLayout layout = VK_NULL_HANDLE; VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers @@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings BoundStorageBufferData sbuf; }; }; - QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT]; + QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT]; friend class QRhiVulkan; }; diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 3c1a052f37..efc79a1783 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -2096,10 +2096,11 @@ uint qHash(const QFont &font, uint seed) noexcept */ bool QFont::fromString(const QString &descrip) { - const auto l = descrip.splitRef(QLatin1Char(',')); - - int count = l.count(); - if (!count || (count > 2 && count < 9) || count > 11) { + const QStringRef sr = QStringRef(&descrip).trimmed(); + const auto l = sr.split(QLatin1Char(',')); + const int count = l.count(); + if (!count || (count > 2 && count < 9) || count > 11 || + l.first().isEmpty()) { qWarning("QFont::fromString: Invalid description '%s'", descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data()); return false; |