diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-09-11 01:00:09 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-09-11 01:00:09 +0200 |
commit | dc4ecf0641de34836c51947a14abdc419204ef6d (patch) | |
tree | bbcfc40e90b39aacf7d62538416a70115165b293 /src/gui | |
parent | 49362d064fffe350600f5324fb510b381578d04a (diff) | |
parent | 66a4001fa28de5d3eac03c2662556d2d5511b0a3 (diff) | |
download | qtbase-dc4ecf0641de34836c51947a14abdc419204ef6d.tar.gz |
Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: Ie69d40d2efc5559b31e28ba71f88e3cda741e051
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/image/qiconloader.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 12 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling.cpp | 2 | ||||
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 17 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 2 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 116 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11_p_p.h | 10 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 63 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 229 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal_p_p.h | 1 | ||||
-rw-r--r-- | src/gui/rhi/qrhinull.cpp | 5 | ||||
-rw-r--r-- | src/gui/rhi/qrhinull_p_p.h | 1 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 5 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p_p.h | 1 | ||||
-rw-r--r-- | src/gui/text/qtextdocument.cpp | 5 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 15 | ||||
-rw-r--r-- | src/gui/text/qtextformat.cpp | 1 |
19 files changed, 336 insertions, 157 deletions
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 1d0c93f26f..27c82bc09f 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -281,7 +281,7 @@ static quint32 icon_name_hash(const char *p) QVector<const char *> QIconCacheGtkReader::lookup(const QStringRef &name) { QVector<const char *> ret; - if (!isValid()) + if (!isValid() || name.isEmpty()) return ret; QByteArray nameUtf8 = name.toUtf8(); diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index cb7a0b8ac9..47bd5727a9 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2762,7 +2762,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To QWindow *window = e->window.data(); typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints; QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents; - bool stationaryTouchPointChangedVelocity = false; + bool stationaryTouchPointChangedProperty = false; for (int i = 0; i < e->points.count(); ++i) { QTouchEvent::TouchPoint touchPoint = e->points.at(i); @@ -2842,7 +2842,11 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To if (touchPoint.state() == Qt::TouchPointStationary) { if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) { touchInfo.touchPoint.setVelocity(touchPoint.velocity()); - stationaryTouchPointChangedVelocity = true; + stationaryTouchPointChangedProperty = true; + } + if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) { + touchInfo.touchPoint.setPressure(touchPoint.pressure()); + stationaryTouchPointChangedProperty = true; } } else { touchInfo.touchPoint = touchPoint; @@ -2883,7 +2887,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To break; case Qt::TouchPointStationary: // don't send the event if nothing changed - if (!stationaryTouchPointChangedVelocity) + if (!stationaryTouchPointChangedProperty) continue; Q_FALLTHROUGH(); default: @@ -3501,7 +3505,7 @@ Qt::ApplicationState QGuiApplication::applicationState() \since 5.14 Sets the high-DPI scale factor rounding policy for the application. The - policy decides how non-integer scale factors (such as Windows 150%) are + \a policy decides how non-integer scale factors (such as Windows 150%) are handled, for applications that have AA_EnableHighDpiScaling enabled. The two principal options are whether fractional scale factors should diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp index ec4feeba8b..dcbae4f5c0 100644 --- a/src/gui/kernel/qhighdpiscaling.cpp +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -538,7 +538,7 @@ void QHighDpiScaling::updateHighDpiScaling() ++i; } } - m_active = m_globalScalingActive || m_usePixelDensity; + m_active = m_globalScalingActive || m_screenFactorSet || m_usePixelDensity; } /* diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 4414b61d55..88d2f73541 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -5020,6 +5020,23 @@ QRhiProfiler *QRhi::profiler() } /*! + Attempts to release resources in the backend's caches. This can include both + CPU and GPU resources. Only memory and resources that can be recreated + automatically are in scope. As an example, if the backend's + QRhiGraphicsPipeline implementation maintains a cache of shader compilation + results, calling this function leads to emptying that cache, thus + potentially freeing up memory and graphics resources. + + Calling this function makes sense in resource constrained environments, + where at a certain point there is a need to ensure minimal resource usage, + at the expense of performance. + */ +void QRhi::releaseCachedResources() +{ + d->releaseCachedResources(); +} + +/*! \return a new graphics pipeline resource. \sa QRhiResource::release() diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 2d36c19e99..928d1f8fa7 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1420,6 +1420,8 @@ public: static const int MAX_LAYERS = 6; // cubemaps only static const int MAX_LEVELS = 16; // a width and/or height of 65536 should be enough for everyone + void releaseCachedResources(); + protected: QRhi(); diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 0914cf268b..b69757ae6d 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -157,6 +157,7 @@ public: virtual const QRhiNativeHandles *nativeHandles() = 0; virtual void sendVMemStatsToProfiler() = 0; virtual void makeThreadLocalNativeContextCurrent() = 0; + virtual void releaseCachedResources() = 0; bool isCompressedFormat(QRhiTexture::Format format) const; void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, @@ -205,6 +206,8 @@ public: QRhi *q; + static const int MAX_SHADER_CACHE_ENTRIES = 128; + protected: bool debugMarkers = false; int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11. diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 9e8533be23..93eadc047d 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -267,10 +267,20 @@ bool QRhiD3D11::create(QRhi::Flags flags) return true; } +void QRhiD3D11::clearShaderCache() +{ + for (Shader &s : m_shaderCache) + s.s->Release(); + + m_shaderCache.clear(); +} + void QRhiD3D11::destroy() { finishActiveReadbacks(); + clearShaderCache(); + if (annotations) { annotations->Release(); annotations = nullptr; @@ -461,6 +471,11 @@ void QRhiD3D11::makeThreadLocalNativeContextCurrent() // nothing to do here } +void QRhiD3D11::releaseCachedResources() +{ + clearShaderCache(); +} + QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { @@ -3408,30 +3423,57 @@ bool QD3D11GraphicsPipeline::build() QByteArray vsByteCode; for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) { - QString error; - QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error); - if (bytecode.isEmpty()) { - qWarning("HLSL shader compilation failed: %s", qPrintable(error)); - return false; - } - switch (shaderStage.type()) { - case QRhiShaderStage::Vertex: - hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs); - if (FAILED(hr)) { - qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr))); - return false; + auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage); + if (cacheIt != rhiD->m_shaderCache.constEnd()) { + switch (shaderStage.type()) { + case QRhiShaderStage::Vertex: + vs = static_cast<ID3D11VertexShader *>(cacheIt->s); + vs->AddRef(); + vsByteCode = cacheIt->bytecode; + break; + case QRhiShaderStage::Fragment: + fs = static_cast<ID3D11PixelShader *>(cacheIt->s); + fs->AddRef(); + break; + default: + break; } - vsByteCode = bytecode; - break; - case QRhiShaderStage::Fragment: - hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs); - if (FAILED(hr)) { - qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr))); + } else { + QString error; + const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error); + if (bytecode.isEmpty()) { + qWarning("HLSL shader compilation failed: %s", qPrintable(error)); return false; } - break; - default: - break; + + if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) { + // Use the simplest strategy: too many cached shaders -> drop them all. + rhiD->clearShaderCache(); + } + + switch (shaderStage.type()) { + case QRhiShaderStage::Vertex: + hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs); + if (FAILED(hr)) { + qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + vsByteCode = bytecode; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode)); + vs->AddRef(); + break; + case QRhiShaderStage::Fragment: + hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs); + if (FAILED(hr)) { + qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode)); + fs->AddRef(); + break; + default: + break; + } } } @@ -3501,19 +3543,31 @@ bool QD3D11ComputePipeline::build() QRHI_RES_RHI(QRhiD3D11); - QString error; - QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); - if (bytecode.isEmpty()) { - qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); - return false; - } + auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage); + if (cacheIt != rhiD->m_shaderCache.constEnd()) { + cs = static_cast<ID3D11ComputeShader *>(cacheIt->s); + } else { + QString error; + const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); + if (bytecode.isEmpty()) { + qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); + return false; + } - HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs); - if (FAILED(hr)) { - qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); - return false; + HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs); + if (FAILED(hr)) { + qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + + if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) + rhiD->clearShaderCache(); + + rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode)); } + cs->AddRef(); + generation += 1; rhiD->registerResource(this); return true; diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 582146315d..cd44519aaa 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -632,6 +632,7 @@ public: const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; void makeThreadLocalNativeContextCurrent() override; + void releaseCachedResources() override; void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); @@ -646,6 +647,7 @@ public: DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const; void finishActiveReadbacks(); void reportLiveObjects(ID3D11Device *device); + void clearShaderCache(); bool debugLayer = false; bool importedDevice = false; @@ -684,6 +686,14 @@ public: QRhiTexture::Format format; }; QVector<ActiveReadback> activeReadbacks; + + struct Shader { + Shader() = default; + Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { } + IUnknown *s; + QByteArray bytecode; + }; + QHash<QRhiShaderStage, Shader> m_shaderCache; }; Q_DECLARE_TYPEINFO(QRhiD3D11::ActiveReadback, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index f4e711e33e..9ad591a17a 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -502,6 +502,10 @@ void QRhiGles2::destroy() ensureContext(); executeDeferredReleases(); + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); + m_shaderCache.clear(); + if (!importedContext) { delete ctx; ctx = nullptr; @@ -757,6 +761,17 @@ void QRhiGles2::makeThreadLocalNativeContextCurrent() ensureContext(); } +void QRhiGles2::releaseCachedResources() +{ + if (!ensureContext()) + return; + + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); + + m_shaderCache.clear(); +} + QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { @@ -2673,7 +2688,6 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type) bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderDescription *desc, int *glslVersionUsed) { - GLuint shader = f->glCreateShader(toGlShaderType(shaderStage.type())); const QShader bakedShader = shaderStage.shader(); QVector<int> versionsToTry; QByteArray source; @@ -2733,27 +2747,40 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage return false; } - const char *srcStr = source.constData(); - const GLint srcLength = source.count(); - f->glShaderSource(shader, 1, &srcStr, &srcLength); - f->glCompileShader(shader); - GLint compiled = 0; - f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLogLength = 0; - f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); - QByteArray log; - if (infoLogLength > 1) { - GLsizei length = 0; - log.resize(infoLogLength); - f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data()); + GLuint shader; + auto cacheIt = m_shaderCache.constFind(shaderStage); + if (cacheIt != m_shaderCache.constEnd()) { + shader = *cacheIt; + } else { + shader = f->glCreateShader(toGlShaderType(shaderStage.type())); + const char *srcStr = source.constData(); + const GLint srcLength = source.count(); + f->glShaderSource(shader, 1, &srcStr, &srcLength); + f->glCompileShader(shader); + GLint compiled = 0; + f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLogLength = 0; + f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + QByteArray log; + if (infoLogLength > 1) { + GLsizei length = 0; + log.resize(infoLogLength); + f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data()); + } + qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData()); + return false; } - qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData()); - return false; + if (m_shaderCache.count() >= MAX_SHADER_CACHE_ENTRIES) { + // Use the simplest strategy: too many cached shaders -> drop them all. + for (uint shader : m_shaderCache) + f->glDeleteShader(shader); // does not actually get released yet when attached to a not-yet-released program + m_shaderCache.clear(); + } + m_shaderCache.insert(shaderStage, shader); } f->glAttachShader(program, shader); - f->glDeleteShader(shader); *desc = bakedShader.description(); return true; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 6da529be92..877eb88d27 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -665,6 +665,7 @@ public: const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; void makeThreadLocalNativeContextCurrent() override; + void releaseCachedResources() override; bool ensureContext(QSurface *surface = nullptr) const; void executeDeferredReleases(); @@ -804,6 +805,8 @@ public: bool active = false; QGles2CommandBuffer cbWrapper; } ofr; + + QHash<QRhiShaderStage, uint> m_shaderCache; }; Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index dfa79edb00..a14ffa7173 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -138,6 +138,20 @@ QT_BEGIN_NAMESPACE \l{QRhiCommandBuffer::endPass()}. */ +struct QMetalShader +{ + id<MTLLibrary> lib = nil; + id<MTLFunction> func = nil; + std::array<uint, 3> localSize; + + void release() { + [lib release]; + lib = nil; + [func release]; + func = nil; + } +}; + struct QRhiMetalData { QRhiMetalData(QRhiImplementation *rhi) : ofr(rhi) { } @@ -206,6 +220,8 @@ struct QRhiMetalData API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil; static const int TEXBUF_ALIGN = 256; // probably not accurate + + QHash<QRhiShaderStage, QMetalShader> shaderCache; }; Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE); @@ -289,17 +305,14 @@ struct QMetalGraphicsPipelineData MTLPrimitiveType primitiveType; MTLWinding winding; MTLCullMode cullMode; - id<MTLLibrary> vsLib = nil; - id<MTLFunction> vsFunc = nil; - id<MTLLibrary> fsLib = nil; - id<MTLFunction> fsFunc = nil; + QMetalShader vs; + QMetalShader fs; }; struct QMetalComputePipelineData { id<MTLComputePipelineState> ps = nil; - id<MTLLibrary> csLib = nil; - id<MTLFunction> csFunc = nil; + QMetalShader cs; MTLSize localSize; }; @@ -404,6 +417,10 @@ void QRhiMetal::destroy() executeDeferredReleases(true); finishActiveReadbacks(true); + for (QMetalShader &s : d->shaderCache) + s.release(); + d->shaderCache.clear(); + if (@available(macOS 10.13, iOS 11.0, *)) { [d->captureScope release]; d->captureScope = nil; @@ -570,6 +587,14 @@ void QRhiMetal::makeThreadLocalNativeContextCurrent() // nothing to do here } +void QRhiMetal::releaseCachedResources() +{ + for (QMetalShader &s : d->shaderCache) + s.release(); + + d->shaderCache.clear(); +} + QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { @@ -2843,36 +2868,17 @@ void QMetalGraphicsPipeline::release() { QRHI_RES_RHI(QRhiMetal); - if (!d->ps) - return; - - if (d->ps) { - [d->ps release]; - d->ps = nil; - } + d->vs.release(); + d->fs.release(); - if (d->ds) { - [d->ds release]; - d->ds = nil; - } + [d->ds release]; + d->ds = nil; - if (d->vsFunc) { - [d->vsFunc release]; - d->vsFunc = nil; - } - if (d->vsLib) { - [d->vsLib release]; - d->vsLib = nil; - } + if (!d->ps) + return; - if (d->fsFunc) { - [d->fsFunc release]; - d->fsFunc = nil; - } - if (d->fsLib) { - [d->fsLib release]; - d->fsLib = nil; - } + [d->ps release]; + d->ps = nil; rhiD->unregisterResource(this); } @@ -3159,34 +3165,66 @@ bool QMetalGraphicsPipeline::build() // buffers not just the resource binding layout) so leave it at the default for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) { - QString error; - QByteArray entryPoint; - id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint); - if (!lib) { - qWarning("MSL shader compilation failed: %s", qPrintable(error)); - return false; - } - id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint); - if (!func) { - qWarning("MSL function for entry point %s not found", entryPoint.constData()); - [lib release]; - return false; - } - switch (shaderStage.type()) { - case QRhiShaderStage::Vertex: - rpDesc.vertexFunction = func; - d->vsLib = lib; - d->vsFunc = func; - break; - case QRhiShaderStage::Fragment: - rpDesc.fragmentFunction = func; - d->fsLib = lib; - d->fsFunc = func; - break; - default: - [func release]; - [lib release]; - break; + auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage); + if (cacheIt != rhiD->d->shaderCache.constEnd()) { + switch (shaderStage.type()) { + case QRhiShaderStage::Vertex: + d->vs = *cacheIt; + [d->vs.lib retain]; + [d->vs.func retain]; + rpDesc.vertexFunction = d->vs.func; + break; + case QRhiShaderStage::Fragment: + d->fs = *cacheIt; + [d->fs.lib retain]; + [d->fs.func retain]; + rpDesc.fragmentFunction = d->fs.func; + break; + default: + break; + } + } else { + QString error; + QByteArray entryPoint; + id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint); + if (!lib) { + qWarning("MSL shader compilation failed: %s", qPrintable(error)); + return false; + } + id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint); + if (!func) { + qWarning("MSL function for entry point %s not found", entryPoint.constData()); + [lib release]; + return false; + } + if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) { + // Use the simplest strategy: too many cached shaders -> drop them all. + for (QMetalShader &s : rhiD->d->shaderCache) + s.release(); + rhiD->d->shaderCache.clear(); + } + switch (shaderStage.type()) { + case QRhiShaderStage::Vertex: + d->vs.lib = lib; + d->vs.func = func; + rhiD->d->shaderCache.insert(shaderStage, d->vs); + [d->vs.lib retain]; + [d->vs.func retain]; + rpDesc.vertexFunction = func; + break; + case QRhiShaderStage::Fragment: + d->fs.lib = lib; + d->fs.func = func; + rhiD->d->shaderCache.insert(shaderStage, d->fs); + [d->fs.lib retain]; + [d->fs.func retain]; + rpDesc.fragmentFunction = func; + break; + default: + [func release]; + [lib release]; + break; + } } } @@ -3286,22 +3324,13 @@ void QMetalComputePipeline::release() { QRHI_RES_RHI(QRhiMetal); - if (d->csFunc) { - [d->csFunc release]; - d->csFunc = nil; - } - if (d->csLib) { - [d->csLib release]; - d->csLib = nil; - } + d->cs.release(); if (!d->ps) return; - if (d->ps) { - [d->ps release]; - d->ps = nil; - } + [d->ps release]; + d->ps = nil; rhiD->unregisterResource(this); } @@ -3313,28 +3342,44 @@ bool QMetalComputePipeline::build() QRHI_RES_RHI(QRhiMetal); - const QShader shader = m_shaderStage.shader(); - QString error; - QByteArray entryPoint; - id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(), - &error, &entryPoint); - if (!lib) { - qWarning("MSL shader compilation failed: %s", qPrintable(error)); - return false; - } - id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint); - if (!func) { - qWarning("MSL function for entry point %s not found", entryPoint.constData()); - [lib release]; - return false; + auto cacheIt = rhiD->d->shaderCache.constFind(m_shaderStage); + if (cacheIt != rhiD->d->shaderCache.constEnd()) { + d->cs = *cacheIt; + } else { + const QShader shader = m_shaderStage.shader(); + QString error; + QByteArray entryPoint; + id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(), + &error, &entryPoint); + if (!lib) { + qWarning("MSL shader compilation failed: %s", qPrintable(error)); + return false; + } + id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint); + if (!func) { + qWarning("MSL function for entry point %s not found", entryPoint.constData()); + [lib release]; + return false; + } + d->cs.lib = lib; + d->cs.func = func; + d->cs.localSize = shader.description().computeShaderLocalSize(); + + if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) { + for (QMetalShader &s : rhiD->d->shaderCache) + s.release(); + rhiD->d->shaderCache.clear(); + } + rhiD->d->shaderCache.insert(m_shaderStage, d->cs); } - d->csLib = lib; - d->csFunc = func; - std::array<uint, 3> localSize = shader.description().computeShaderLocalSize(); - d->localSize = MTLSizeMake(localSize[0], localSize[1], localSize[2]); + + [d->cs.lib retain]; + [d->cs.func retain]; + + d->localSize = MTLSizeMake(d->cs.localSize[0], d->cs.localSize[1], d->cs.localSize[2]); NSError *err = nil; - d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->csFunc error: &err]; + d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->cs.func error: &err]; if (!d->ps) { const QString msg = QString::fromNSString(err.localizedDescription); qWarning("Failed to create render pipeline state: %s", qPrintable(msg)); diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index c448865f4d..01b0bf4f56 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -417,6 +417,7 @@ public: const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; void makeThreadLocalNativeContextCurrent() override; + void releaseCachedResources() override; void executeDeferredReleases(bool forced = false); void finishActiveReadbacks(bool forced = false); diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index dff6e05268..29a3968bfc 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -174,6 +174,11 @@ void QRhiNull::makeThreadLocalNativeContextCurrent() // nothing to do here } +void QRhiNull::releaseCachedResources() +{ + // nothing to do here +} + QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index bdf0d59724..b43f830d5e 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -283,6 +283,7 @@ public: const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; void makeThreadLocalNativeContextCurrent() override; + void releaseCachedResources() override; QRhiNullNativeHandles nativeHandlesStruct; QRhiSwapChain *currentSwapChain = nullptr; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index dfc85fb853..4f550c6a90 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3744,6 +3744,11 @@ void QRhiVulkan::makeThreadLocalNativeContextCurrent() // nothing to do here } +void QRhiVulkan::releaseCachedResources() +{ + // nothing to do here +} + QRhiRenderBuffer *QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) { diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 962a1b8eb7..23cc80b814 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -712,6 +712,7 @@ public: const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; void makeThreadLocalNativeContextCurrent() override; + void releaseCachedResources() override; VkResult createDescriptorPool(VkDescriptorPool *pool); bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex); diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index c80617f929..3652a180a8 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2067,8 +2067,9 @@ void QTextDocument::print(QPagedPaintDevice *printer) const \enum QTextDocument::ResourceType This enum describes the types of resources that can be loaded by - QTextDocument's loadResource() function. + QTextDocument's loadResource() function or by QTextBrowser::setSource(). + \value UnknownResource No resource is loaded, or the resource type is not known. \value HtmlResource The resource contains HTML. \value ImageResource The resource contains image data. Currently supported data types are QVariant::Pixmap and @@ -2082,7 +2083,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const \value UserResource The first available value for user defined resource types. - \sa loadResource() + \sa loadResource(), QTextBrowser::sourceType() */ /*! diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index c267ade0c2..b37353bf2c 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -399,6 +399,7 @@ struct QBidiAlgorithm { analysis[i].bidiDirection = (level & 1) ? QChar::DirR : QChar::DirL; runHasContent = true; lastRunWithContent = -1; + ++isolatePairPosition; } int runBeforeIsolate = runs.size(); ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.top().level + 2) & ~1); @@ -440,21 +441,19 @@ struct QBidiAlgorithm { doEmbed(true, true, false); break; case QChar::DirLRI: - Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i); doEmbed(false, false, true); - ++isolatePairPosition; break; case QChar::DirRLI: - Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i); doEmbed(true, false, true); - ++isolatePairPosition; break; case QChar::DirFSI: { - const auto &pair = isolatePairs.at(isolatePairPosition); - Q_ASSERT(pair.start == i); - bool isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft(); + bool isRtl = false; + if (isolatePairPosition < isolatePairs.size()) { + const auto &pair = isolatePairs.at(isolatePairPosition); + Q_ASSERT(pair.start == i); + isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft(); + } doEmbed(isRtl, false, true); - ++isolatePairPosition; break; } diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 47a38db3ad..e3bd49a15e 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -650,6 +650,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) \value TableColumns \value TableColumnWidthConstraints \value TableHeaderRowCount + \value TableBorderCollapse Specifies the \l QTextTableFormat::borderCollapse property. Table cell properties |