summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/image/qimage.cpp6
-rw-r--r--src/gui/kernel/qguiapplication.cpp23
-rw-r--r--src/gui/kernel/qguiapplication_p.h2
-rw-r--r--src/gui/kernel/qkeysequence.cpp6
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp6
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h3
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h3
-rw-r--r--src/gui/opengl/qopenglfunctions_4_2_compatibility.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_2_core.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_3_compatibility.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_3_core.h11
-rw-r--r--src/gui/opengl/qopenglfunctions_4_4_compatibility.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_4_core.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_5_compatibility.h10
-rw-r--r--src/gui/opengl/qopenglfunctions_4_5_core.h11
-rw-r--r--src/gui/opengl/qopenglversionfunctions.h10
-rw-r--r--src/gui/rhi/qrhi.cpp26
-rw-r--r--src/gui/rhi/qrhigles2.cpp6
-rw-r--r--src/gui/rhi/qrhimetal.mm161
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h7
-rw-r--r--src/gui/rhi/qshader.cpp144
-rw-r--r--src/gui/rhi/qshader_p.h5
-rw-r--r--src/gui/rhi/qshader_p_p.h4
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp8
-rw-r--r--src/gui/text/qtextengine.cpp24
25 files changed, 420 insertions, 106 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index dda407181a..2779b97fbd 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -4145,11 +4145,11 @@ QPaintEngine *QImage::paintEngine() const
if (!d->paintEngine) {
QPaintDevice *paintDevice = const_cast<QImage *>(this);
- QPaintEngine *paintEngine = 0;
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
if (platformIntegration)
- paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
- d->paintEngine = paintEngine ? paintEngine : new QRasterPaintEngine(paintDevice);
+ d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
+ if (!d->paintEngine)
+ d->paintEngine = new QRasterPaintEngine(paintDevice);
}
return d->paintEngine;
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index fa4c419ef0..f4a5c0e104 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1869,7 +1869,20 @@ bool QGuiApplication::event(QEvent *e)
{
if(e->type() == QEvent::LanguageChange) {
setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight);
+ } else if (e->type() == QEvent::Quit) {
+ // Close open windows. This is done in order to deliver de-expose
+ // events while the event loop is still running.
+ for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) {
+ // Already closed windows will not have a platform window, skip those
+ if (!topLevelWindow->handle())
+ continue;
+ if (!topLevelWindow->close()) {
+ e->ignore();
+ return true;
+ }
+ }
}
+
return QCoreApplication::event(e);
}
@@ -1946,6 +1959,9 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
break;
+ case QWindowSystemInterfacePrivate::ApplicationTermination:
+ QGuiApplicationPrivate::processApplicationTermination(e);
+ break;
case QWindowSystemInterfacePrivate::FlushEvents: {
QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
@@ -3495,6 +3511,13 @@ bool QGuiApplicationPrivate::tryCloseRemainingWindows(QWindowList processedWindo
return true;
}
+void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent)
+{
+ QEvent event(QEvent::Quit);
+ QGuiApplication::sendSpontaneousEvent(QGuiApplication::instance(), &event);
+ windowSystemEvent->eventAccepted = event.isAccepted();
+}
+
/*!
\since 5.2
\fn Qt::ApplicationState QGuiApplication::applicationState()
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 73d137619e..56a3be1122 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -144,6 +144,8 @@ public:
static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e);
+ static void processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *e);
+
static void updateFilteredScreenOrientation(QScreen *screen);
static void reportScreenOrientationChange(QScreen *screen);
static void processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e);
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 25766467eb..d5bdf1f15b 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -490,6 +490,8 @@ static const struct {
{ Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") },
{ Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") },
{ Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") },
+ { Qt::Key_LaunchG, QT_TRANSLATE_NOOP("QShortcut", "Launch (G)") },
+ { Qt::Key_LaunchH, QT_TRANSLATE_NOOP("QShortcut", "Launch (H)") },
{ Qt::Key_MonBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Up") },
{ Qt::Key_MonBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Down") },
{ Qt::Key_KeyboardLightOnOff, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Light On/Off") },
@@ -516,9 +518,11 @@ static const struct {
{ Qt::Key_Book, QT_TRANSLATE_NOOP("QShortcut", "Book") },
{ Qt::Key_CD, QT_TRANSLATE_NOOP("QShortcut", "CD") },
{ Qt::Key_Calculator, QT_TRANSLATE_NOOP("QShortcut", "Calculator") },
+ { Qt::Key_Calendar, QT_TRANSLATE_NOOP("QShortcut", "Calendar") },
{ Qt::Key_Clear, QT_TRANSLATE_NOOP("QShortcut", "Clear") },
{ Qt::Key_ClearGrab, QT_TRANSLATE_NOOP("QShortcut", "Clear Grab") },
{ Qt::Key_Close, QT_TRANSLATE_NOOP("QShortcut", "Close") },
+ { Qt::Key_ContrastAdjust, QT_TRANSLATE_NOOP("QShortcut", "Adjust contrast") },
{ Qt::Key_Copy, QT_TRANSLATE_NOOP("QShortcut", "Copy") },
{ Qt::Key_Cut, QT_TRANSLATE_NOOP("QShortcut", "Cut") },
{ Qt::Key_Display, QT_TRANSLATE_NOOP("QShortcut", "Display") },
@@ -532,6 +536,7 @@ static const struct {
{ Qt::Key_LogOff, QT_TRANSLATE_NOOP("QShortcut", "Logoff") },
{ Qt::Key_Market, QT_TRANSLATE_NOOP("QShortcut", "Market") },
{ Qt::Key_Meeting, QT_TRANSLATE_NOOP("QShortcut", "Meeting") },
+ { Qt::Key_Memo, QT_TRANSLATE_NOOP("QShortcut", "Memo") },
{ Qt::Key_MenuKB, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Menu") },
{ Qt::Key_MenuPB, QT_TRANSLATE_NOOP("QShortcut", "Menu PB") },
{ Qt::Key_MySites, QT_TRANSLATE_NOOP("QShortcut", "My Sites") },
@@ -552,6 +557,7 @@ static const struct {
{ Qt::Key_Support, QT_TRANSLATE_NOOP("QShortcut", "Support") },
{ Qt::Key_TaskPane, QT_TRANSLATE_NOOP("QShortcut", "Task Panel") },
{ Qt::Key_Terminal, QT_TRANSLATE_NOOP("QShortcut", "Terminal") },
+ { Qt::Key_ToDoList, QT_TRANSLATE_NOOP("QShortcut", "To-do list") },
{ Qt::Key_Tools, QT_TRANSLATE_NOOP("QShortcut", "Tools") },
{ Qt::Key_Travel, QT_TRANSLATE_NOOP("QShortcut", "Travel") },
{ Qt::Key_Video, QT_TRANSLATE_NOOP("QShortcut", "Video") },
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 5ae8013b82..71780ed609 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -285,6 +285,12 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleApplicationStateChanged, Qt::Application
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
+QT_DEFINE_QPA_EVENT_HANDLER(bool, handleApplicationTermination)
+{
+ auto *e = new QWindowSystemInterfacePrivate::WindowSystemEvent(QWindowSystemInterfacePrivate::ApplicationTermination);
+ return QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
+}
+
QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window, const QRect &newGeometry)
: WindowSystemEvent(GeometryChange)
, window(window)
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index 4a0bc858a9..d5a4ad30d8 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -215,6 +215,9 @@ public:
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate = false);
+ template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
+ static bool handleApplicationTermination();
+
#if QT_CONFIG(draganddrop)
#if QT_DEPRECATED_SINCE(5, 11)
QT_DEPRECATED static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData,
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 55fd181ef0..6e4bce607e 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -99,7 +99,8 @@ public:
ApplicationStateChanged = 0x19,
FlushEvents = 0x20,
WindowScreenChanged = 0x21,
- SafeAreaMarginsChanged = 0x22
+ SafeAreaMarginsChanged = 0x22,
+ ApplicationTermination = 0x23
};
class WindowSystemEvent {
diff --git a/src/gui/opengl/qopenglfunctions_4_2_compatibility.h b/src/gui/opengl/qopenglfunctions_4_2_compatibility.h
index 6726d5fc44..a48d581c2d 100644
--- a/src/gui/opengl/qopenglfunctions_4_2_compatibility.h
+++ b/src/gui/opengl/qopenglfunctions_4_2_compatibility.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Compatibility : public QAbstractOpenGLFunctions
@@ -5632,6 +5638,10 @@ inline void QOpenGLFunctions_4_2_Compatibility::glVertexAttribI1i(GLuint index,
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_2_core.h b/src/gui/opengl/qopenglfunctions_4_2_core.h
index a921329741..5ca98e9808 100644
--- a/src/gui/opengl/qopenglfunctions_4_2_core.h
+++ b/src/gui/opengl/qopenglfunctions_4_2_core.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_2_Core : public QAbstractOpenGLFunctions
@@ -3027,6 +3033,10 @@ inline void QOpenGLFunctions_4_2_Core::glDrawArraysInstancedBaseInstance(GLenum
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_3_compatibility.h b/src/gui/opengl/qopenglfunctions_4_3_compatibility.h
index b9d4eb1d6f..d969f5b3b4 100644
--- a/src/gui/opengl/qopenglfunctions_4_3_compatibility.h
+++ b/src/gui/opengl/qopenglfunctions_4_3_compatibility.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Compatibility : public QAbstractOpenGLFunctions
@@ -5839,6 +5845,10 @@ inline void QOpenGLFunctions_4_3_Compatibility::glVertexAttribI1i(GLuint index,
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_3_core.h b/src/gui/opengl/qopenglfunctions_4_3_core.h
index da552d64af..13675caf62 100644
--- a/src/gui/opengl/qopenglfunctions_4_3_core.h
+++ b/src/gui/opengl/qopenglfunctions_4_3_core.h
@@ -57,6 +57,13 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_3_Core : public QAbstractOpenGLFunctions
@@ -3230,6 +3237,10 @@ inline void QOpenGLFunctions_4_3_Core::glClearBufferData(GLenum target, GLenum i
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_4_compatibility.h b/src/gui/opengl/qopenglfunctions_4_4_compatibility.h
index 7a05bd802d..0acab349a1 100644
--- a/src/gui/opengl/qopenglfunctions_4_4_compatibility.h
+++ b/src/gui/opengl/qopenglfunctions_4_4_compatibility.h
@@ -59,6 +59,12 @@
QT_BEGIN_NAMESPACE
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Compatibility : public QAbstractOpenGLFunctions
{
public:
@@ -5961,6 +5967,10 @@ inline void QOpenGLFunctions_4_4_Compatibility::glVertexP2ui(GLenum type, GLuint
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_4_core.h b/src/gui/opengl/qopenglfunctions_4_4_core.h
index 6b29a9659b..1ad6f40214 100644
--- a/src/gui/opengl/qopenglfunctions_4_4_core.h
+++ b/src/gui/opengl/qopenglfunctions_4_4_core.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_4_Core : public QAbstractOpenGLFunctions
@@ -3415,6 +3421,10 @@ inline void QOpenGLFunctions_4_4_Core::glBufferStorage(GLenum target, GLsizeiptr
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_5_compatibility.h b/src/gui/opengl/qopenglfunctions_4_5_compatibility.h
index a809c1c90b..9d9d14548b 100644
--- a/src/gui/opengl/qopenglfunctions_4_5_compatibility.h
+++ b/src/gui/opengl/qopenglfunctions_4_5_compatibility.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Compatibility : public QAbstractOpenGLFunctions
@@ -6679,6 +6685,10 @@ inline void QOpenGLFunctions_4_5_Compatibility::glGetnMapdv(GLenum target, GLenu
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglfunctions_4_5_core.h b/src/gui/opengl/qopenglfunctions_4_5_core.h
index bb1b17f7b1..bf872c628b 100644
--- a/src/gui/opengl/qopenglfunctions_4_5_core.h
+++ b/src/gui/opengl/qopenglfunctions_4_5_core.h
@@ -57,6 +57,12 @@
#include <QtGui/QOpenGLVersionFunctions>
#include <QtGui/qopenglcontext.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLFunctions_4_5_Core : public QAbstractOpenGLFunctions
@@ -4056,6 +4062,11 @@ inline void QOpenGLFunctions_4_5_Core::glClipControl(GLenum origin, GLenum depth
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
+
#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
#endif
diff --git a/src/gui/opengl/qopenglversionfunctions.h b/src/gui/opengl/qopenglversionfunctions.h
index aa6e49b9ae..4835ea4871 100644
--- a/src/gui/opengl/qopenglversionfunctions.h
+++ b/src/gui/opengl/qopenglversionfunctions.h
@@ -61,6 +61,12 @@
#include <QtCore/qpair.h>
#include <QtGui/qopengl.h>
+// MemoryBarrier is a macro on some architectures on Windows
+#ifdef Q_OS_WIN
+#pragma push_macro("MemoryBarrier")
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class QOpenGLContext;
@@ -1897,6 +1903,10 @@ public:
QT_END_NAMESPACE
+#ifdef Q_OS_WIN
+#pragma pop_macro("MemoryBarrier")
+#endif
+
#endif // QT_NO_OPENGL
#endif
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index dabad35688..8ef98d2e42 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -3518,14 +3518,36 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
\c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be
resized.
+ \note Typical rendering logic will call this function to get the output
+ size when starting to prepare a new frame, and base dependent calculations
+ (such as, the viewport) on the size returned from this function.
+
+ While in many cases the value is the same as \c{QWindow::size() *
+ QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not
+ guaranteed to be correct on all platforms and graphics API implementations.
+ Using this function is therefore strongly recommended whenever there is a
+ need to identify the dimensions, in pixels, of the output layer or surface.
+
+ This also has the added benefit of avoiding potential data races when QRhi
+ is used on a dedicated rendering thread, because the need to call QWindow
+ functions, that may then access data updated on the main thread, is
+ avoided.
+
\sa surfacePixelSize()
*/
/*!
\fn QSize QRhiSwapChain::surfacePixelSize()
- \return The size of the window's associated surface or layer. Do not assume
- this is the same as QWindow::size() * QWindow::devicePixelRatio().
+ \return The size of the window's associated surface or layer.
+
+ \warning Do not assume this is the same as \c{QWindow::size() *
+ QWindow::devicePixelRatio()}. With some graphics APIs and windowing system
+ interfaces (for example, Vulkan) there is a theoretical possibility for a
+ surface to assume a size different from the associated window. To support
+ these cases, rendering logic must always base size-derived calculations
+ (such as, viewports) on the size reported from QRhiSwapChain, and never on
+ the size queried from QWindow.
\note Can also be called before buildOrResize(), if at least window() is
already set) This in combination with currentPixelSize() allows to detect
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index dec28cac9b..abee843a74 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -2961,7 +2961,7 @@ bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
return checker.get(ctx)->isSupported();
}
-static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
+Q_GLOBAL_STATIC(QOpenGLProgramBinaryCache, qrhi_programBinaryCache);
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
{
@@ -2995,7 +2995,7 @@ QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage
}
diskCacheKey = binaryProgram.cacheKey();
- if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
+ if (qrhi_programBinaryCache()->load(diskCacheKey, program)) {
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
program, diskCacheKey.constData());
result = QRhiGles2::DiskCacheHit;
@@ -3013,7 +3013,7 @@ 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);
+ qrhi_programBinaryCache()->save(cacheKey, program);
}
}
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 5f14d917b8..131b2da802 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -35,8 +35,6 @@
****************************************************************************/
#include "qrhimetal_p_p.h"
-#include "qshader_p.h"
-#include "qshaderdescription_p.h"
#include <QGuiApplication>
#include <QWindow>
#include <qmath.h>
@@ -143,8 +141,10 @@ struct QMetalShader
id<MTLLibrary> lib = nil;
id<MTLFunction> func = nil;
std::array<uint, 3> localSize;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
void release() {
+ nativeResourceBindingMap.clear();
[lib release];
lib = nil;
[func release];
@@ -164,7 +164,7 @@ struct QRhiMetalData
const QRhiDepthStencilClearValue &depthStencilClearValue,
int colorAttCount);
id<MTLLibrary> createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
- QString *error, QByteArray *entryPoint);
+ QString *error, QByteArray *entryPoint, QShaderKey *activeKey);
id<MTLFunction> createMSLShaderFunction(id<MTLLibrary> lib, const QByteArray &entryPoint);
struct DeferredReleaseEntry {
@@ -653,18 +653,40 @@ QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings()
return new QMetalShaderResourceBindings(this);
}
-void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
+enum class BindingType {
+ Buffer,
+ Texture,
+ Sampler
+};
+
+static inline int mapBinding(int binding,
+ int stageIndex,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[],
+ BindingType type)
+{
+ const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
+ if (map) {
+ auto it = map->constFind(binding);
+ if (it != map->cend())
+ return type == BindingType::Sampler ? it->second : it->first;
+ }
+ return binding;
+}
+
+void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
+ QMetalCommandBuffer *cbD,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
- bool offsetOnlyChange)
+ bool offsetOnlyChange,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES])
{
- static const int KNOWN_STAGES = 3;
struct {
QRhiBatchedBindings<id<MTLBuffer> > buffers;
QRhiBatchedBindings<NSUInteger> bufferOffsets;
QRhiBatchedBindings<id<MTLTexture> > textures;
QRhiBatchedBindings<id<MTLSamplerState> > samplers;
- } res[KNOWN_STAGES];
+ } res[SUPPORTED_STAGES];
+ enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 };
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBinding::Data *b = binding.data();
@@ -682,16 +704,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[0].buffers.feed(b->binding, mtlbuf);
- res[0].bufferOffsets.feed(b->binding, offset);
+ res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[VERTEX].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[1].buffers.feed(b->binding, mtlbuf);
- res[1].bufferOffsets.feed(b->binding, offset);
+ res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[2].buffers.feed(b->binding, mtlbuf);
- res[2].bufferOffsets.feed(b->binding, offset);
+ res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[COMPUTE].bufferOffsets.feed(b->binding, offset);
}
}
break;
@@ -700,16 +722,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[0].textures.feed(b->binding, texD->d->tex);
- res[0].samplers.feed(b->binding, samplerD->d->samplerState);
+ res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
+ res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[1].textures.feed(b->binding, texD->d->tex);
- res[1].samplers.feed(b->binding, samplerD->d->samplerState);
+ res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
+ res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[2].textures.feed(b->binding, texD->d->tex);
- res[2].samplers.feed(b->binding, samplerD->d->samplerState);
+ res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
+ res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
}
break;
@@ -722,11 +744,11 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
- res[0].textures.feed(b->binding, t);
+ res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t);
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
- res[1].textures.feed(b->binding, t);
+ res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t);
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
- res[2].textures.feed(b->binding, t);
+ res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t);
}
break;
case QRhiShaderResourceBinding::BufferLoad:
@@ -739,16 +761,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
uint offset = uint(b->u.sbuf.offset);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[0].buffers.feed(b->binding, mtlbuf);
- res[0].bufferOffsets.feed(b->binding, offset);
+ res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[VERTEX].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[1].buffers.feed(b->binding, mtlbuf);
- res[1].bufferOffsets.feed(b->binding, offset);
+ res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[2].buffers.feed(b->binding, mtlbuf);
- res[2].bufferOffsets.feed(b->binding, offset);
+ res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
+ res[COMPUTE].bufferOffsets.feed(b->binding, offset);
}
}
break;
@@ -758,25 +780,30 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
- for (int idx = 0; idx < KNOWN_STAGES; ++idx) {
- res[idx].buffers.finish();
- res[idx].bufferOffsets.finish();
+ for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
+ if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == VERTEX || stage == FRAGMENT))
+ continue;
+ if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == COMPUTE)
+ continue;
+
+ res[stage].buffers.finish();
+ res[stage].bufferOffsets.finish();
- for (int i = 0, ie = res[idx].buffers.batches.count(); i != ie; ++i) {
- const auto &bufferBatch(res[idx].buffers.batches[i]);
- const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
- switch (idx) {
- case 0:
+ for (int i = 0, ie = res[stage].buffers.batches.count(); i != ie; ++i) {
+ const auto &bufferBatch(res[stage].buffers.batches[i]);
+ const auto &offsetBatch(res[stage].bufferOffsets.batches[i]);
+ switch (stage) {
+ case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
- case 1:
+ case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
- case 2:
+ case COMPUTE:
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
@@ -790,21 +817,21 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
if (offsetOnlyChange)
continue;
- res[idx].textures.finish();
- res[idx].samplers.finish();
+ res[stage].textures.finish();
+ res[stage].samplers.finish();
- for (int i = 0, ie = res[idx].textures.batches.count(); i != ie; ++i) {
- const auto &batch(res[idx].textures.batches[i]);
- switch (idx) {
- case 0:
+ for (int i = 0, ie = res[stage].textures.batches.count(); i != ie; ++i) {
+ const auto &batch(res[stage].textures.batches[i]);
+ switch (stage) {
+ case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
- case 1:
+ case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
- case 2:
+ case COMPUTE:
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
@@ -813,18 +840,18 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
break;
}
}
- for (int i = 0, ie = res[idx].samplers.batches.count(); i != ie; ++i) {
- const auto &batch(res[idx].samplers.batches[i]);
- switch (idx) {
- case 0:
+ for (int i = 0, ie = res[stage].samplers.batches.count(); i != ie; ++i) {
+ const auto &batch(res[stage].samplers.batches[i]);
+ switch (stage) {
+ case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
- case 1:
+ case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
- case 2:
+ case COMPUTE:
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
@@ -973,18 +1000,22 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
// dynamic uniform buffer offsets always trigger a rebind
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) {
+ const QShader::NativeResourceBindingMap *resBindMaps[SUPPORTED_STAGES] = { nullptr, nullptr, nullptr };
if (gfxPsD) {
cbD->currentGraphicsSrb = srb;
cbD->currentComputeSrb = nullptr;
+ resBindMaps[0] = &gfxPsD->d->vs.nativeResourceBindingMap;
+ resBindMaps[1] = &gfxPsD->d->fs.nativeResourceBindingMap;
} else {
cbD->currentGraphicsSrb = nullptr;
cbD->currentComputeSrb = srb;
+ resBindMaps[2] = &compPsD->d->cs.nativeResourceBindingMap;
}
cbD->currentSrbGeneration = srbD->generation;
cbD->currentResSlot = resSlot;
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
- enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange);
+ enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange, resBindMaps);
}
}
@@ -3081,9 +3112,10 @@ static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c)
}
id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
- QString *error, QByteArray *entryPoint)
+ QString *error, QByteArray *entryPoint, QShaderKey *activeKey)
{
- QShaderCode mtllib = shader.shader({ QShader::MetalLibShader, 12, shaderVariant });
+ QShaderKey key = { QShader::MetalLibShader, 12, shaderVariant };
+ QShaderCode mtllib = shader.shader(key);
if (!mtllib.shader().isEmpty()) {
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
size_t(mtllib.shader().size()),
@@ -3094,6 +3126,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
dispatch_release(data);
if (!err) {
*entryPoint = mtllib.entryPoint();
+ *activeKey = key;
return lib;
} else {
const QString msg = QString::fromNSString(err.localizedDescription);
@@ -3101,7 +3134,8 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
}
}
- QShaderCode mslSource = shader.shader({ QShader::MslShader, 12, shaderVariant });
+ key = { QShader::MslShader, 12, shaderVariant };
+ QShaderCode mslSource = shader.shader(key);
if (mslSource.shader().isEmpty()) {
qWarning() << "No MSL 1.2 code found in baked shader" << shader;
return nil;
@@ -3122,6 +3156,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
}
*entryPoint = mslSource.entryPoint();
+ *activeKey = key;
return lib;
}
@@ -3195,9 +3230,12 @@ bool QMetalGraphicsPipeline::build()
break;
}
} else {
+ const QShader shader = shaderStage.shader();
QString error;
QByteArray entryPoint;
- id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
+ QShaderKey activeKey;
+ id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, shaderStage.shaderVariant(),
+ &error, &entryPoint, &activeKey);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
@@ -3218,6 +3256,8 @@ bool QMetalGraphicsPipeline::build()
case QRhiShaderStage::Vertex:
d->vs.lib = lib;
d->vs.func = func;
+ if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
+ d->vs.nativeResourceBindingMap = *map;
rhiD->d->shaderCache.insert(shaderStage, d->vs);
[d->vs.lib retain];
[d->vs.func retain];
@@ -3226,6 +3266,8 @@ bool QMetalGraphicsPipeline::build()
case QRhiShaderStage::Fragment:
d->fs.lib = lib;
d->fs.func = func;
+ if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
+ d->fs.nativeResourceBindingMap = *map;
rhiD->d->shaderCache.insert(shaderStage, d->fs);
[d->fs.lib retain];
[d->fs.func retain];
@@ -3360,8 +3402,9 @@ bool QMetalComputePipeline::build()
const QShader shader = m_shaderStage.shader();
QString error;
QByteArray entryPoint;
+ QShaderKey activeKey;
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
- &error, &entryPoint);
+ &error, &entryPoint, &activeKey);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
@@ -3375,6 +3418,8 @@ bool QMetalComputePipeline::build()
d->cs.lib = lib;
d->cs.func = func;
d->cs.localSize = shader.description().computeShaderLocalSize();
+ if (const QShader::NativeResourceBindingMap *map = shader.nativeResourceBindingMap(activeKey))
+ d->cs.nativeResourceBindingMap = *map;
if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
for (QMetalShader &s : rhiD->d->shaderCache)
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
index 688fec8147..2be86db5c8 100644
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ b/src/gui/rhi/qrhimetal_p_p.h
@@ -433,10 +433,13 @@ public:
qsizetype *curOfs);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
- void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
+ static const int SUPPORTED_STAGES = 3;
+ void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
+ QMetalCommandBuffer *cbD,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
- bool offsetOnlyChange);
+ bool offsetOnlyChange,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
int effectiveSampleCount(int sampleCount) const;
bool importedDevice = false;
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 6a2c596557..c22b029dc8 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -214,7 +214,8 @@ QT_BEGIN_NAMESPACE
QShader, it indicates no shader code was found for the requested key.
*/
-static const int QSB_VERSION = 1;
+static const int QSB_VERSION = 2;
+static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
/*!
Constructs a new, empty (and thus invalid) QShader instance.
@@ -345,6 +346,14 @@ void QShader::removeShader(const QShaderKey &key)
d->shaders.erase(it);
}
+static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
+{
+ *ds << k.source();
+ *ds << k.sourceVersion().version();
+ *ds << k.sourceVersion().flags();
+ *ds << k.sourceVariant();
+}
+
/*!
\return a serialized binary version of all the data held by the
QShader, suitable for writing to files or other I/O devices.
@@ -365,18 +374,42 @@ QByteArray QShader::serialized() const
ds << d->shaders.count();
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
- ds << k.source();
- ds << k.sourceVersion().version();
- ds << k.sourceVersion().flags();
- ds << k.sourceVariant();
+ writeShaderKey(&ds, k);
const QShaderCode &shader(d->shaders.value(k));
ds << shader.shader();
ds << shader.entryPoint();
}
+ ds << d->bindings.count();
+ for (auto it = d->bindings.cbegin(), itEnd = d->bindings.cend(); it != itEnd; ++it) {
+ const QShaderKey &k(it.key());
+ writeShaderKey(&ds, k);
+ const NativeResourceBindingMap &map(it.value());
+ ds << map.count();
+ for (auto mapIt = map.cbegin(), mapItEnd = map.cend(); mapIt != mapItEnd; ++mapIt) {
+ ds << mapIt.key();
+ ds << mapIt.value().first;
+ ds << mapIt.value().second;
+ }
+ }
return qCompress(buf.buffer());
}
+static void readShaderKey(QDataStream *ds, QShaderKey *k)
+{
+ int intVal;
+ *ds >> intVal;
+ k->setSource(QShader::Source(intVal));
+ QShaderVersion ver;
+ *ds >> intVal;
+ ver.setVersion(intVal);
+ *ds >> intVal;
+ ver.setFlags(QShaderVersion::Flags(intVal));
+ k->setSourceVersion(ver);
+ *ds >> intVal;
+ k->setSourceVariant(QShader::Variant(intVal));
+}
+
/*!
Creates a new QShader instance from the given \a data.
@@ -396,8 +429,11 @@ QShader QShader::fromSerialized(const QByteArray &data)
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
int intVal;
ds >> intVal;
- if (intVal != QSB_VERSION)
+ const int qsbVersion = intVal;
+ if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
+ qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion);
return QShader();
+ }
ds >> intVal;
d->stage = Stage(intVal);
@@ -408,16 +444,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
ds >> count;
for (int i = 0; i < count; ++i) {
QShaderKey k;
- ds >> intVal;
- k.setSource(Source(intVal));
- QShaderVersion ver;
- ds >> intVal;
- ver.setVersion(intVal);
- ds >> intVal;
- ver.setFlags(QShaderVersion::Flags(intVal));
- k.setSourceVersion(ver);
- ds >> intVal;
- k.setSourceVariant(Variant(intVal));
+ readShaderKey(&ds, &k);
QShaderCode shader;
QByteArray s;
ds >> s;
@@ -427,6 +454,27 @@ QShader QShader::fromSerialized(const QByteArray &data)
d->shaders[k] = shader;
}
+ if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
+ ds >> count;
+ for (int i = 0; i < count; ++i) {
+ QShaderKey k;
+ readShaderKey(&ds, &k);
+ NativeResourceBindingMap map;
+ int mapSize;
+ ds >> mapSize;
+ for (int b = 0; b < mapSize; ++b) {
+ int binding;
+ ds >> binding;
+ int firstNativeBinding;
+ ds >> firstNativeBinding;
+ int secondNativeBinding;
+ ds >> secondNativeBinding;
+ map.insert(binding, { firstNativeBinding, secondNativeBinding });
+ }
+ d->bindings.insert(k, map);
+ }
+ }
+
return bs;
}
@@ -460,7 +508,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) Q_DECL_NOTHROW
{
return lhs.d->stage == rhs.d->stage
&& lhs.d->shaders == rhs.d->shaders;
- // do not bother with desc, if the shader code is the same, the description must match too
+ // do not bother with desc and bindings, if the shader code is the same, the description must match too
}
/*!
@@ -586,4 +634,66 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v)
}
#endif // QT_NO_DEBUG_STREAM
+/*!
+ \typedef QShader::NativeResourceBindingMap
+
+ Synonym for QHash<int, QPair<int, int>>.
+
+ The resource binding model QRhi assumes is based on SPIR-V. This means that
+ uniform buffers, storage buffers, combined image samplers, and storage
+ images share a common binding point space. The binding numbers in
+ QShaderDescription and QRhiShaderResourceBinding are expected to match the
+ \c binding layout qualifier in the Vulkan-compatible GLSL shader.
+
+ Graphics APIs other than Vulkan may use a resource binding model that is
+ not fully compatible with this. In addition, the generator of the shader
+ code translated from SPIR-V may choose not to take the SPIR-V binding
+ qualifiers into account, for various reasons. (this is the case with the
+ Metal backend of SPIRV-Cross, for example).
+
+ Therefore, a QShader may expose an additional map that describes what the
+ native binding point for a given SPIR-V binding is. The QRhi backends are
+ expected to use this map automatically, as appropriate. The value is a
+ pair, because combined image samplers may map to two native resources (a
+ texture and a sampler) in some shading languages. In that case the second
+ value refers to the sampler.
+*/
+
+/*!
+ \return the native binding map for \a key or null if no extra mapping is
+ available, or is not applicable.
+ */
+const QShader::NativeResourceBindingMap *QShader::nativeResourceBindingMap(const QShaderKey &key) const
+{
+ auto it = d->bindings.constFind(key);
+ if (it == d->bindings.cend())
+ return nullptr;
+
+ return &it.value();
+}
+
+/*!
+ Stores the given native resource binding \a map associated with \a key.
+
+ \sa nativeResourceBindingMap()
+ */
+void QShader::setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map)
+{
+ detach();
+ d->bindings[key] = map;
+}
+
+/*!
+ Removes the native resource binding map for \a key.
+ */
+void QShader::removeResourceBindingMap(const QShaderKey &key)
+{
+ auto it = d->bindings.find(key);
+ if (it == d->bindings.end())
+ return;
+
+ detach();
+ d->bindings.erase(it);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qshader_p.h b/src/gui/rhi/qshader_p.h
index 243842a95a..4b561b6fa9 100644
--- a/src/gui/rhi/qshader_p.h
+++ b/src/gui/rhi/qshader_p.h
@@ -149,6 +149,11 @@ public:
QByteArray serialized() const;
static QShader fromSerialized(const QByteArray &data);
+ using NativeResourceBindingMap = QHash<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
+ const NativeResourceBindingMap *nativeResourceBindingMap(const QShaderKey &key) const;
+ void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
+ void removeResourceBindingMap(const QShaderKey &key);
+
private:
QShaderPrivate *d;
friend struct QShaderPrivate;
diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h
index 6473590e95..4535e01491 100644
--- a/src/gui/rhi/qshader_p_p.h
+++ b/src/gui/rhi/qshader_p_p.h
@@ -66,7 +66,8 @@ struct Q_GUI_EXPORT QShaderPrivate
: ref(1),
stage(other->stage),
desc(other->desc),
- shaders(other->shaders)
+ shaders(other->shaders),
+ bindings(other->bindings)
{
}
@@ -77,6 +78,7 @@ struct Q_GUI_EXPORT QShaderPrivate
QShader::Stage stage = QShader::VertexStage;
QShaderDescription desc;
QHash<QShaderKey, QShaderCode> shaders;
+ QHash<QShaderKey, QShader::NativeResourceBindingMap> bindings;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index 7be114adf9..ed23a4d8d9 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -2088,8 +2088,12 @@ void QTextDocumentLayoutPrivate::drawBlock(const QPointF &offset, QPainter *pain
tl->draw(painter, offset, selections, context.clip.isValid() ? (context.clip & clipRect) : clipRect);
- if ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen)
- || (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty())) {
+ // if the block is empty and it precedes a table, do not draw the cursor.
+ // the cursor is drawn later after the table has been drawn so no need
+ // to draw it here.
+ if (!isEmptyBlockBeforeTable(frameIteratorForTextPosition(blpos))
+ && ((context.cursorPosition >= blpos && context.cursorPosition < blpos + bllen)
+ || (context.cursorPosition < -1 && !tl->preeditAreaText().isEmpty()))) {
int cpos = context.cursorPosition;
if (cpos < -1)
cpos = tl->preeditAreaPosition() - (cpos + 2);
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index b37353bf2c..209433dac5 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2125,22 +2125,7 @@ void QTextEngine::itemize() const
}
#if QT_CONFIG(harfbuzz)
analysis = scriptAnalysis.data();
- if (qt_useHarfbuzzNG()) {
- // ### pretend HB-old behavior for now
- for (int i = 0; i < length; ++i) {
- switch (analysis[i].script) {
- case QChar::Script_Latin:
- case QChar::Script_Hiragana:
- case QChar::Script_Katakana:
- case QChar::Script_Bopomofo:
- case QChar::Script_Han:
- analysis[i].script = QChar::Script_Common;
- break;
- default:
- break;
- }
- }
- } else {
+ if (!qt_useHarfbuzzNG()) {
for (int i = 0; i < length; ++i)
analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script));
}
@@ -3619,7 +3604,12 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
int clusterLength = 0;
if (si->analysis.script != QChar::Script_Common &&
- si->analysis.script != QChar::Script_Greek) {
+ si->analysis.script != QChar::Script_Greek &&
+ si->analysis.script != QChar::Script_Latin &&
+ si->analysis.script != QChar::Script_Hiragana &&
+ si->analysis.script != QChar::Script_Katakana &&
+ si->analysis.script != QChar::Script_Bopomofo &&
+ si->analysis.script != QChar::Script_Han) {
if (glyph_pos == -1)
return si->position + end;
else {