summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/doc/src/richtext.qdoc8
-rw-r--r--src/gui/image/qbmphandler_p.h2
-rw-r--r--src/gui/image/qiconloader.cpp8
-rw-r--r--src/gui/image/qimage_conversions.cpp13
-rw-r--r--src/gui/image/qimagereader.cpp4
-rw-r--r--src/gui/image/qimagewriter.cpp19
-rw-r--r--src/gui/image/qpixmap.cpp2
-rw-r--r--src/gui/kernel/qevent.cpp46
-rw-r--r--src/gui/kernel/qevent.h16
-rw-r--r--src/gui/kernel/qguiapplication.cpp5
-rw-r--r--src/gui/kernel/qkeysequence.cpp2
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp2
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp4
-rw-r--r--src/gui/opengl/qopengl.cpp2
-rw-r--r--src/gui/painting/qdrawhelper.cpp30
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp29
-rw-r--r--src/gui/painting/qdrawhelper_x86_p.h3
-rw-r--r--src/gui/painting/qpaintengine.cpp2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp7
-rw-r--r--src/gui/rhi/qrhigles2.cpp272
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h87
-rw-r--r--src/gui/text/qfontengine.cpp2
-rw-r--r--src/gui/util/qvalidator.cpp9
24 files changed, 418 insertions, 158 deletions
diff --git a/src/gui/doc/src/richtext.qdoc b/src/gui/doc/src/richtext.qdoc
index b7c731cf43..a963124849 100644
--- a/src/gui/doc/src/richtext.qdoc
+++ b/src/gui/doc/src/richtext.qdoc
@@ -1191,16 +1191,16 @@
\li none | dotted | dashed | dot-dash | dot-dot-dash | solid | double | groove | ridge | inset | outset
\li Border style for text tables and table cells.
\row \li \c border-top-style
- \li <color>
+ \li <border-style>
\li Top border style for table cells.
\row \li \c border-bottom-style
- \li <color>
+ \li <border-style>
\li Bottom border style for table cells.
\row \li \c border-left-style
- \li <color>
+ \li <border-style>
\li Left border style for table cells.
\row \li \c border-right-style
- \li <color>
+ \li <border-style>
\li Right border style for table cells.
\row \li \c border-width
\li <width>px
diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h
index fd044fc442..e1d744e539 100644
--- a/src/gui/image/qbmphandler_p.h
+++ b/src/gui/image/qbmphandler_p.h
@@ -98,7 +98,7 @@ struct BMP_INFOHDR { // BMP information header
// BMP-Handler, which is also able to read and write the DIB
// (Device-Independent-Bitmap) format used internally in the Windows operating
// system for OLE/clipboard operations. DIB is a subset of BMP (without file
-// header). The Windows-Lighthouse plugin accesses the DIB-functionality.
+// header). The Windows platform plugin accesses the DIB-functionality.
class QBmpHandler : public QImageIOHandler
{
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index e67b387981..15ab1b3cd9 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -797,8 +797,12 @@ QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State
if (svgIcon.isNull())
svgIcon = QIcon(filename);
- // Simply reuse svg icon engine
- return svgIcon.pixmap(size, mode, state);
+ // Bypass QIcon API, as that will scale by device pixel ratio of the
+ // highest DPR screen since we're not passing on any QWindow.
+ if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr)
+ return engine->pixmap(size, mode, state);
+
+ return QPixmap();
}
QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 6ddd08d08d..34d2b8d8c7 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -48,6 +48,11 @@
#if QT_CONFIG(thread)
#include <qsemaphore.h>
#include <qthreadpool.h>
+#ifdef Q_OS_WASM
+// WebAssembly has threads; however we can't block the main thread.
+#else
+#define QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
+#endif
#endif
QT_BEGIN_NAMESPACE
@@ -227,7 +232,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
}
};
-#if QT_CONFIG(thread)
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = src->nbytes / (1<<16);
segments = std::min(segments, src->height);
@@ -281,7 +286,7 @@ void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::Image
destData += dest->bytes_per_line;
}
};
-#if QT_CONFIG(thread)
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = src->nbytes / (1<<16);
segments = std::min(segments, src->height);
@@ -388,7 +393,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
destData += params.bytesPerLine;
}
};
-#if QT_CONFIG(thread)
+#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS
int segments = data->nbytes / (1<<16);
segments = std::min(segments, data->height);
if (segments > 1) {
@@ -426,8 +431,8 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
data->nbytes = params.totalSize;
}
data->bytes_per_line = params.bytesPerLine;
- data->depth = destDepth;
}
+ data->depth = destDepth;
data->format = dst_format;
return true;
}
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 3eb1e01863..5cb7e1328e 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -101,7 +101,7 @@
This can be disabled by setting the environment variable
\c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING.
- \sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase
+ \sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase, QColorSpace
\sa QImage::devicePixelRatio(), QPixmap::devicePixelRatio(), QIcon, QPainter::drawPixmap(), QPainter::drawImage(), Qt::AA_UseHighDpiPixmaps
*/
@@ -1152,6 +1152,7 @@ bool QImageReader::autoTransform() const
#if QT_DEPRECATED_SINCE(5, 15)
/*!
\since 5.6
+ \obsolete Use QColorSpace conversion on the QImage instead.
This is an image format specific function that forces images with
gamma information to be gamma corrected to \a gamma. For image formats
@@ -1169,6 +1170,7 @@ void QImageReader::setGamma(float gamma)
/*!
\since 5.6
+ \obsolete Use QImage::colorSpace() and QColorSpace::gamma() instead.
Returns the gamma level of the decoded image. If setGamma() has been
called and gamma correction is supported it will return the gamma set.
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index 6e74b23f76..33f5e491c7 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -47,19 +47,18 @@
\ingroup painting
\ingroup io
- QImageWriter supports setting format specific options, such as the
- gamma level, compression level and quality, prior to storing the
+ QImageWriter supports setting format specific options, such as
+ compression level and quality, prior to storing the
image. If you do not need such options, you can use QImage::save()
or QPixmap::save() instead.
To store an image, you start by constructing a QImageWriter
object. Pass either a file name or a device pointer, and the
image format to QImageWriter's constructor. You can then set
- several options, such as the gamma level (by calling setGamma())
- and quality (by calling setQuality()). canWrite() returns \c true if
- QImageWriter can write the image (i.e., the image format is
- supported and the device is open for writing). Call write() to
- write the image to the device.
+ several options, such as quality (by calling setQuality()).
+ canWrite() returns \c true if QImageWriter can write the image
+ (i.e., the image format is supported and the device is open for
+ writing). Call write() to write the image to the device.
If any error occurs when writing the image, write() will return
false. You can then call error() to find the type of error that
@@ -81,7 +80,7 @@
\snippet qimagewriter/main.cpp 0
- \sa QImageReader, QImageIOHandler, QImageIOPlugin
+ \sa QImageReader, QImageIOHandler, QImageIOPlugin, QColorSpace
*/
/*!
@@ -500,6 +499,8 @@ int QImageWriter::compression() const
#if QT_DEPRECATED_SINCE(5, 15)
/*!
+ \obsolete Use QColorSpace conversion on the QImage instead.
+
This is an image format specific function that sets the gamma
level of the image to \a gamma. For image formats that do not
support setting the gamma level, this value is ignored.
@@ -515,6 +516,8 @@ void QImageWriter::setGamma(float gamma)
}
/*!
+ \obsolete Use QImage::colorSpace() and QColorSpace::gamma() instead.
+
Returns the gamma level of the image.
\sa setGamma()
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index c162b706cb..a4c5296d9f 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -78,7 +78,7 @@ static bool qt_pixmap_thread_test()
if (qApp->thread() != QThread::currentThread()) {
bool fail = false;
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) {
- printf("Lighthouse plugin does not support threaded pixmaps!\n");
+ printf("Platform plugin does not support threaded pixmaps!\n");
fail = true;
}
if (fail) {
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 1716cbc557..dc49d8b324 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -2224,14 +2224,14 @@ QVariant QInputMethodQueryEvent::value(Qt::InputMethodQuery query) const
(pressing the stylus tip against the tablet surface is equivalent to a left
mouse button). But tablet events also pass through some extra information
that the tablet device driver provides; for example, you might want to do
- subpixel rendering with higher resolution coordinates (\l hiResGlobalX()
- and \l hiResGlobalY()), adjust color brightness based on the \l pressure()
- of the tool against the tablet surface, use different brushes depending on
- the type of tool in use (\l device()), modulate the brush shape in some way
- according to the X-axis and Y-axis tilt of the tool with respect to the
- tablet surface (\l xTilt() and \l yTilt()), and use a virtual eraser
- instead of a brush if the user switches to the other end of a double-ended
- stylus (\l pointerType()).
+ subpixel rendering with higher resolution coordinates (\l globalPosF()),
+ adjust color brightness based on the \l pressure() of the tool against the
+ tablet surface, use different brushes depending on the type of tool in use
+ (\l deviceType()), modulate the brush shape in some way according to the
+ X-axis and Y-axis tilt of the tool with respect to the tablet surface
+ (\l xTilt() and \l yTilt()), and use a virtual eraser instead of a brush if
+ the user switches to the other end of a double-ended stylus
+ (\l pointerType()).
Every event contains an accept flag that indicates whether the receiver
wants the event. You should call QTabletEvent::accept() if you handle the
@@ -4572,19 +4572,12 @@ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const
return d->lastNormalizedPos;
}
+#if QT_DEPRECATED_SINCE(5, 15)
/*!
- Returns the rect for this touch point, relative to the widget
- or QGraphicsItem that received the event. The rect is centered
- around the point returned by pos().
-
- \note This function returns an empty rect if the device does not report touch point sizes.
-
- \obsolete This function is deprecated in 5.9 because it returns the outer bounds
+ \deprecated This function is deprecated since 5.9 because it returns the outer bounds
of the touchpoint regardless of rotation, whereas a touchpoint is more correctly
modeled as an ellipse at position pos() with ellipseDiameters()
which are independent of rotation().
-
- \sa scenePos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::rect() const
{
@@ -4594,16 +4587,10 @@ QRectF QTouchEvent::TouchPoint::rect() const
}
/*!
- Returns the rect for this touch point in scene coordinates.
-
- \note This function returns an empty rect if the device does not report touch point sizes.
-
- \obsolete This function is deprecated in 5.9 because it returns the outer bounds
+ \deprecated This function is deprecated since 5.9 because it returns the outer bounds
of the touchpoint regardless of rotation, whereas a touchpoint is more correctly
modeled as an ellipse at position scenePos() with ellipseDiameters()
which are independent of rotation().
-
- \sa scenePos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::sceneRect() const
{
@@ -4613,16 +4600,10 @@ QRectF QTouchEvent::TouchPoint::sceneRect() const
}
/*!
- Returns the rect for this touch point in screen coordinates.
-
- \note This function returns an empty rect if the device does not report touch point sizes.
-
- \obsolete This function is deprecated because it returns the outer bounds of the
+ \deprecated This function is deprecated since 5.9 because it returns the outer bounds of the
touchpoint regardless of rotation, whereas a touchpoint is more correctly
modeled as an ellipse at position screenPos() with ellipseDiameters()
which are independent of rotation().
-
- \sa screenPos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::screenRect() const
{
@@ -4630,6 +4611,7 @@ QRectF QTouchEvent::TouchPoint::screenRect() const
ret.moveCenter(d->screenPos);
return ret;
}
+#endif
/*!
Returns the pressure of this touch point. The return value is in
@@ -4828,6 +4810,7 @@ void QTouchEvent::TouchPoint::setLastNormalizedPos(const QPointF &lastNormalized
d->lastNormalizedPos = lastNormalizedPos;
}
+#if QT_DEPRECATED_SINCE(5, 15)
// ### remove the following 3 setRect functions and their usages soon
/*! \internal
\obsolete
@@ -4861,6 +4844,7 @@ void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect)
d->screenPos = screenRect.center();
d->ellipseDiameters = screenRect.size();
}
+#endif
/*! \internal */
void QTouchEvent::TouchPoint::setPressure(qreal pressure)
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 8a4acec257..05d79ad803 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -888,10 +888,23 @@ public:
QPointF startNormalizedPos() const;
QPointF lastNormalizedPos() const;
+#if QT_DEPRECATED_SINCE(5, 15)
+ // All these are actually deprecated since 5.9, in docs
+ QT_DEPRECATED_VERSION_X_5_15("Use pos() and ellipseDiameters()")
QRectF rect() const;
+ QT_DEPRECATED_VERSION_X_5_15("Use scenePos() and ellipseDiameters()")
QRectF sceneRect() const;
+ QT_DEPRECATED_VERSION_X_5_15("Use screenPos() and ellipseDiameters()")
QRectF screenRect() const;
+ // internal
+ QT_DEPRECATED_VERSION_X_5_15("Use setPos() and setEllipseDiameters()")
+ void setRect(const QRectF &rect); // deprecated
+ QT_DEPRECATED_VERSION_X_5_15("Use setScenePos() and setEllipseDiameters()")
+ void setSceneRect(const QRectF &sceneRect); // deprecated
+ QT_DEPRECATED_VERSION_X_5_15("Use setScreenPos() and setEllipseDiameters()")
+ void setScreenRect(const QRectF &screenRect); // deprecated
+#endif
qreal pressure() const;
qreal rotation() const;
QSizeF ellipseDiameters() const;
@@ -916,9 +929,6 @@ public:
void setLastScenePos(const QPointF &lastScenePos);
void setLastScreenPos(const QPointF &lastScreenPos);
void setLastNormalizedPos(const QPointF &lastNormalizedPos);
- void setRect(const QRectF &rect); // deprecated
- void setSceneRect(const QRectF &sceneRect); // deprecated
- void setScreenRect(const QRectF &screenRect); // deprecated
void setPressure(qreal pressure);
void setRotation(qreal angle);
void setEllipseDiameters(const QSizeF &dia);
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 0ad6272a7c..92256078dc 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -134,6 +134,7 @@ QT_BEGIN_NAMESPACE
return __VA_ARGS__; \
}
+Q_CORE_EXPORT void qt_call_post_routines();
Q_GUI_EXPORT bool qt_is_gui_used = true;
Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
@@ -685,6 +686,8 @@ QGuiApplication::~QGuiApplication()
{
Q_D(QGuiApplication);
+ qt_call_post_routines();
+
d->eventDispatcher->closingDown();
d->eventDispatcher = nullptr;
@@ -2328,7 +2331,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
static bool menuKeyPressAccepted = false;
#endif
-#if !defined(Q_OS_OSX)
+#if !defined(Q_OS_MACOS)
// FIXME: Include OS X in this code path by passing the key event through
// QPlatformInputContext::filterEvent().
if (e->keyType == QEvent::KeyPress && window) {
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 57a89bb8c2..cdcb6e8faf 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -1286,7 +1286,7 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat
QString p = keyName(key, format);
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
if (nativeText)
s += p;
else
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index d2e079b57f..443f5d2552 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -980,7 +980,7 @@ QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDia
const int *QPlatformDialogHelper::buttonLayout(Qt::Orientation orientation, ButtonLayout policy)
{
if (policy == UnknownLayout) {
-#if defined (Q_OS_OSX)
+#if defined (Q_OS_MACOS)
policy = MacLayout;
#elif defined (Q_OS_LINUX) || defined (Q_OS_UNIX)
policy = KdeLayout;
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 9d90bf5db2..e8f0892b95 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -498,7 +498,7 @@ QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, QEvent::Type
QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count)
{
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count))
return true;
#endif
@@ -526,7 +526,7 @@ bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, ulong times
const QString& text, bool autorep,
ushort count, bool tryShortcutOverride)
{
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window,
timestamp, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count)) {
return true;
diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp
index adca536797..3066b83282 100644
--- a/src/gui/opengl/qopengl.cpp
+++ b/src/gui/opengl/qopengl.cpp
@@ -295,7 +295,7 @@ QString OsTypeTerm::hostOs()
return QStringLiteral("win");
#elif defined(Q_OS_LINUX)
return QStringLiteral("linux");
-#elif defined(Q_OS_OSX)
+#elif defined(Q_OS_MACOS)
return QStringLiteral("macosx");
#elif defined(Q_OS_ANDROID)
return QStringLiteral("android");
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index e4e8305620..793986467e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -4482,9 +4482,8 @@ static void blend_color_generic(int count, const QSpan *spans, void *userData)
uint buffer[BufferSize];
Operator op = getOperator(data, nullptr, 0);
const uint color = data->solidColor.toArgb32();
- bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source
- || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && qAlpha(color) == 255);
- QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
+ const bool solidFill = op.mode == QPainter::CompositionMode_Source;
+ const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
while (count--) {
int x = spans->x;
@@ -4522,6 +4521,10 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
if (spans->coverage == 255) {
qt_memfill(target, color, spans->len);
+#ifdef __SSE2__
+ } else if (spans->len > 16) {
+ op.funcSolid(target, spans->len, color, spans->coverage);
+#endif
} else {
uint c = BYTE_MUL(color, spans->coverage);
int ialpha = 255 - spans->coverage;
@@ -4552,9 +4555,8 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
alignas(8) QRgba64 buffer[BufferSize];
const QRgba64 color = data->solidColor;
- bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source
- || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && color.isOpaque());
- QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
+ const bool solidFill = op.mode == QPainter::CompositionMode_Source;
+ const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
while (count--) {
int x = spans->x;
@@ -5137,7 +5139,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
yoff += image_height;
bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
- if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && isBpp32) {
+ bool isBpp64 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP64;
+ if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && (isBpp32 || isBpp64)) {
// If destination isn't blended into the result, we can do the tiling directly on destination pixels.
while (count--) {
int x = spans->x;
@@ -5171,9 +5174,14 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
if (sx >= image_width)
sx = 0;
}
- uint *dest = (uint*)data->rasterBuffer->scanLine(y) + x - image_width;
- for (int i = image_width; i < length; ++i) {
- dest[i] = dest[i - image_width];
+ if (isBpp32) {
+ uint *dest = reinterpret_cast<uint *>(data->rasterBuffer->scanLine(y)) + x - image_width;
+ for (int i = image_width; i < length; ++i)
+ dest[i] = dest[i - image_width];
+ } else {
+ quint64 *dest = reinterpret_cast<quint64 *>(data->rasterBuffer->scanLine(y)) + x - image_width;
+ for (int i = image_width; i < length; ++i)
+ dest[i] = dest[i - image_width];
}
++spans;
}
@@ -6766,10 +6774,12 @@ static void qInitDrawhelperFunctions()
extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha);
extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2;
qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2;
qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
+ qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_sse2;
qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
#ifdef QT_COMPILER_SUPPORTS_SSSE3
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index dd42b96d79..f1ad369906 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -601,7 +601,7 @@ public:
FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD)
break;
default:
- Q_ASSERT(false);
+ Q_UNREACHABLE();
}
}
};
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index c82f41ec88..77b5ab42c5 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -319,6 +319,35 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, qsizetype count)
}
#endif // !__AVX2__
+void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha)
+{
+ if (const_alpha == 255) {
+ qt_memfill32(destPixels, color, length);
+ } else {
+ const quint32 ialpha = 255 - const_alpha;
+ color = BYTE_MUL(color, const_alpha);
+ int x = 0;
+
+ quint32 *dst = (quint32 *) destPixels;
+ const __m128i colorVector = _mm_set1_epi32(color);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i iAlphaVector = _mm_set1_epi16(ialpha);
+
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha);
+
+ for (; x < length-3; x += 4) {
+ __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
+ BYTE_MUL_SSE2(dstVector, dstVector, iAlphaVector, colorMask, half);
+ dstVector = _mm_add_epi8(colorVector, dstVector);
+ _mm_store_si128((__m128i *)&dst[x], dstVector);
+ }
+ SIMD_EPILOGUE(x, length, 3)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha);
+ }
+}
+
void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha)
{
if ((const_alpha & qAlpha(color)) == 255) {
diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h
index 5749d8c9fb..869abcc637 100644
--- a/src/gui/painting/qdrawhelper_x86_p.h
+++ b/src/gui/painting/qdrawhelper_x86_p.h
@@ -77,9 +77,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
int w, int h,
int const_alpha);
-extern CompositionFunction qt_functionForMode_SSE2[];
-extern CompositionFunctionSolid qt_functionForModeSolid_SSE2[];
-
void qt_memfill64_avx2(quint64 *dest, quint64 value, qsizetype count);
void qt_memfill32_avx2(quint32 *dest, quint32 value, qsizetype count);
#endif // __SSE2__
diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp
index 1785fcd12d..fc5c125b72 100644
--- a/src/gui/painting/qpaintengine.cpp
+++ b/src/gui/painting/qpaintengine.cpp
@@ -158,7 +158,7 @@ QFont QTextItem::font() const
X11 and \macos, it is the backend for painting on QImage and it is
used as a fallback for paint engines that do not support a certain
capability. In addition we provide QPaintEngine implementations for
- OpenGL (accessible through QGLWidget) and printing (which allows using
+ OpenGL (accessible through QOpenGLWidget) and printing (which allows using
QPainter to draw on a QPrinter object).
If one wants to use QPainter to draw to a different backend,
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 10920c38fe..5b7f8511ba 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1713,8 +1713,11 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
width / line.length(),
s->lastPen.capStyle() == Qt::SquareCap);
} else {
- d->rasterizeLine_dashed(line, width,
- &dashIndex, &dashOffset, &inDash);
+ // LinesHint means each line is distinct, so restart dashing
+ int dIndex = dashIndex;
+ qreal dOffset = dashOffset;
+ bool inD = inDash;
+ d->rasterizeLine_dashed(line, width, &dIndex, &dOffset, &inD);
}
}
}
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index ea9bce08e4..227dace90f 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -1191,7 +1191,18 @@ void QRhiGles2::beginExternal(QRhiCommandBuffer *cb)
}
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
+
+ if (cbD->recordingPass == QGles2CommandBuffer::ComputePass
+ && !cbD->computePassState.writtenResources.isEmpty())
+ {
+ QGles2CommandBuffer::Command cmd;
+ cmd.cmd = QGles2CommandBuffer::Command::Barrier;
+ cmd.args.barrier.barriers = GL_ALL_BARRIER_BITS;
+ cbD->commands.append(cmd);
+ }
+
executeCommandBuffer(cbD);
+
cbD->resetCommands();
if (vao)
@@ -1931,6 +1942,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
GLenum indexType = GL_UNSIGNED_SHORT;
quint32 indexStride = sizeof(quint16);
quint32 indexOffset = 0;
+ GLuint currentArrayBuffer = 0;
+ static const int TRACKED_ATTRIB_COUNT = 16;
+ bool enabledAttribArrays[TRACKED_ATTRIB_COUNT];
+ memset(enabledAttribArrays, 0, sizeof(enabledAttribArrays));
for (const QGles2CommandBuffer::Command &cmd : qAsConst(cbD->commands)) {
switch (cmd.cmd) {
@@ -1963,8 +1978,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.stencilRef.ps);
if (psD) {
- f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask);
- f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask);
+ const GLint ref = GLint(cmd.args.stencilRef.ref);
+ f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), ref, psD->m_stencilReadMask);
+ f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), ref, psD->m_stencilReadMask);
+ cbD->graphicsPassState.dynamic.stencilRef = ref;
} else {
qWarning("No graphics pipeline active for setStencilRef; ignored");
}
@@ -1981,8 +1998,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
if (bindingIdx != cmd.args.bindVertexBuffer.binding)
continue;
- // we do not support more than one vertex buffer
- f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer);
+ if (cmd.args.bindVertexBuffer.buffer != currentArrayBuffer) {
+ currentArrayBuffer = cmd.args.bindVertexBuffer.buffer;
+ // we do not support more than one vertex buffer
+ f->glBindBuffer(GL_ARRAY_BUFFER, currentArrayBuffer);
+ }
const QRhiVertexInputBinding *inputBinding = psD->m_vertexInputLayout.bindingAt(bindingIdx);
const int stride = int(inputBinding->stride());
@@ -2029,7 +2049,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
quint32 ofs = it->offset() + cmd.args.bindVertexBuffer.offset;
f->glVertexAttribPointer(GLuint(locationIdx), size, type, normalize, stride,
reinterpret_cast<const GLvoid *>(quintptr(ofs)));
- f->glEnableVertexAttribArray(GLuint(locationIdx));
+ if (locationIdx >= TRACKED_ATTRIB_COUNT || !enabledAttribArrays[locationIdx]) {
+ if (locationIdx < TRACKED_ATTRIB_COUNT)
+ enabledAttribArrays[locationIdx] = true;
+ f->glEnableVertexAttribArray(GLuint(locationIdx));
+ }
if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance && caps.instancing)
f->glVertexAttribDivisor(GLuint(locationIdx), GLuint(inputBinding->instanceStepRate()));
}
@@ -2100,7 +2124,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
}
break;
case QGles2CommandBuffer::Command::BindGraphicsPipeline:
- executeBindGraphicsPipeline(cmd.args.bindGraphicsPipeline.ps);
+ executeBindGraphicsPipeline(cbD, QRHI_RES(QGles2GraphicsPipeline, cmd.args.bindGraphicsPipeline.ps));
break;
case QGles2CommandBuffer::Command::BindShaderResources:
bindShaderResources(cmd.args.bindShaderResources.maybeGraphicsPs,
@@ -2146,6 +2170,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT)
f->glClearStencil(GLint(cmd.args.clear.s));
f->glClear(cmd.args.clear.mask);
+ cbD->graphicsPassState.reset(); // altered depth/color write, invalidate in order to avoid confusing the state tracking
break;
case QGles2CommandBuffer::Command::BufferSubData:
f->glBindBuffer(cmd.args.bufferSubData.target, cmd.args.bufferSubData.buffer);
@@ -2326,83 +2351,179 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
}
}
-void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps)
+void QRhiGles2::executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD)
{
- QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, ps);
+ QGles2CommandBuffer::GraphicsPassState &state(cbD->graphicsPassState);
+ const bool forceUpdate = !state.valid;
+ state.valid = true;
- // No state tracking logic as of now. Could introduce something to reduce
- // the number of gl* calls (when using and changing between multiple
- // pipelines), but then begin/endExternal() should invalidate the cached
- // state as appropriate.
+ const bool scissor = psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor);
+ if (forceUpdate || scissor != state.scissor) {
+ state.scissor = scissor;
+ if (scissor)
+ f->glEnable(GL_SCISSOR_TEST);
+ else
+ f->glDisable(GL_SCISSOR_TEST);
+ }
- if (psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
- f->glEnable(GL_SCISSOR_TEST);
- else
- f->glDisable(GL_SCISSOR_TEST);
- if (psD->m_cullMode == QRhiGraphicsPipeline::None) {
- f->glDisable(GL_CULL_FACE);
- } else {
- f->glEnable(GL_CULL_FACE);
- f->glCullFace(toGlCullMode(psD->m_cullMode));
+ const bool cullFace = psD->m_cullMode != QRhiGraphicsPipeline::None;
+ const GLenum cullMode = cullFace ? toGlCullMode(psD->m_cullMode) : GL_NONE;
+ if (forceUpdate || cullFace != state.cullFace || cullMode != state.cullMode) {
+ state.cullFace = cullFace;
+ state.cullMode = cullMode;
+ if (cullFace) {
+ f->glEnable(GL_CULL_FACE);
+ f->glCullFace(cullMode);
+ } else {
+ f->glDisable(GL_CULL_FACE);
+ }
+ }
+
+ const GLenum frontFace = toGlFrontFace(psD->m_frontFace);
+ if (forceUpdate || frontFace != state.frontFace) {
+ state.frontFace = frontFace;
+ f->glFrontFace(frontFace);
}
- f->glFrontFace(toGlFrontFace(psD->m_frontFace));
+
if (!psD->m_targetBlends.isEmpty()) {
- const QRhiGraphicsPipeline::TargetBlend &blend(psD->m_targetBlends.first()); // no MRT
- GLboolean wr = blend.colorWrite.testFlag(QRhiGraphicsPipeline::R);
- GLboolean wg = blend.colorWrite.testFlag(QRhiGraphicsPipeline::G);
- GLboolean wb = blend.colorWrite.testFlag(QRhiGraphicsPipeline::B);
- GLboolean wa = blend.colorWrite.testFlag(QRhiGraphicsPipeline::A);
- f->glColorMask(wr, wg, wb, wa);
- if (blend.enable) {
- f->glEnable(GL_BLEND);
- f->glBlendFuncSeparate(toGlBlendFactor(blend.srcColor),
- toGlBlendFactor(blend.dstColor),
- toGlBlendFactor(blend.srcAlpha),
- toGlBlendFactor(blend.dstAlpha));
- f->glBlendEquationSeparate(toGlBlendOp(blend.opColor), toGlBlendOp(blend.opAlpha));
- } else {
- f->glDisable(GL_BLEND);
+ // We do not have MRT support here, meaning all targets use the blend
+ // params from the first one. This is technically incorrect, even if
+ // nothing in Qt relies on it. However, considering that
+ // glBlendFuncSeparatei is only available in GL 4.0+ and GLES 3.2+, we
+ // may just live with this for now because no point in bothering if it
+ // won't be usable on many GLES (3.1 or 3.0) systems.
+ const QRhiGraphicsPipeline::TargetBlend &targetBlend(psD->m_targetBlends.first());
+
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask colorMask = {
+ targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::R),
+ targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::G),
+ targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::B),
+ targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::A)
+ };
+ if (forceUpdate || colorMask != state.colorMask) {
+ state.colorMask = colorMask;
+ f->glColorMask(colorMask.r, colorMask.g, colorMask.b, colorMask.a);
+ }
+
+ const bool blendEnabled = targetBlend.enable;
+ const QGles2CommandBuffer::GraphicsPassState::Blend blend = {
+ toGlBlendFactor(targetBlend.srcColor),
+ toGlBlendFactor(targetBlend.dstColor),
+ toGlBlendFactor(targetBlend.srcAlpha),
+ toGlBlendFactor(targetBlend.dstAlpha),
+ toGlBlendOp(targetBlend.opColor),
+ toGlBlendOp(targetBlend.opAlpha)
+ };
+ if (forceUpdate || blendEnabled != state.blendEnabled || (blendEnabled && blend != state.blend)) {
+ state.blendEnabled = blendEnabled;
+ if (blendEnabled) {
+ state.blend = blend;
+ f->glEnable(GL_BLEND);
+ f->glBlendFuncSeparate(blend.srcColor, blend.dstColor, blend.srcAlpha, blend.dstAlpha);
+ f->glBlendEquationSeparate(blend.opColor, blend.opAlpha);
+ } else {
+ f->glDisable(GL_BLEND);
+ }
}
} else {
- f->glDisable(GL_BLEND);
- f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask colorMask = { true, true, true, true };
+ if (forceUpdate || colorMask != state.colorMask) {
+ state.colorMask = colorMask;
+ f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+ const bool blendEnabled = false;
+ if (forceUpdate || blendEnabled != state.blendEnabled) {
+ state.blendEnabled = blendEnabled;
+ f->glDisable(GL_BLEND);
+ }
}
- if (psD->m_depthTest)
- f->glEnable(GL_DEPTH_TEST);
- else
- f->glDisable(GL_DEPTH_TEST);
- if (psD->m_depthWrite)
- f->glDepthMask(GL_TRUE);
- else
- f->glDepthMask(GL_FALSE);
- f->glDepthFunc(toGlCompareOp(psD->m_depthOp));
- if (psD->m_stencilTest) {
- f->glEnable(GL_STENCIL_TEST);
- f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), 0, psD->m_stencilReadMask);
- f->glStencilOpSeparate(GL_FRONT,
- toGlStencilOp(psD->m_stencilFront.failOp),
- toGlStencilOp(psD->m_stencilFront.depthFailOp),
- toGlStencilOp(psD->m_stencilFront.passOp));
- f->glStencilMaskSeparate(GL_FRONT, psD->m_stencilWriteMask);
- f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), 0, psD->m_stencilReadMask);
- f->glStencilOpSeparate(GL_BACK,
- toGlStencilOp(psD->m_stencilBack.failOp),
- toGlStencilOp(psD->m_stencilBack.depthFailOp),
- toGlStencilOp(psD->m_stencilBack.passOp));
- f->glStencilMaskSeparate(GL_BACK, psD->m_stencilWriteMask);
- } else {
- f->glDisable(GL_STENCIL_TEST);
+
+ const bool depthTest = psD->m_depthTest;
+ if (forceUpdate || depthTest != state.depthTest) {
+ state.depthTest = depthTest;
+ if (depthTest)
+ f->glEnable(GL_DEPTH_TEST);
+ else
+ f->glDisable(GL_DEPTH_TEST);
}
- if (psD->m_depthBias != 0 || !qFuzzyIsNull(psD->m_slopeScaledDepthBias)) {
- f->glPolygonOffset(psD->m_slopeScaledDepthBias, psD->m_depthBias);
- f->glEnable(GL_POLYGON_OFFSET_FILL);
- } else {
- f->glDisable(GL_POLYGON_OFFSET_FILL);
+ const bool depthWrite = psD->m_depthWrite;
+ if (forceUpdate || depthWrite != state.depthWrite) {
+ state.depthWrite = depthWrite;
+ f->glDepthMask(depthWrite);
+ }
+
+ const GLenum depthFunc = toGlCompareOp(psD->m_depthOp);
+ if (forceUpdate || depthFunc != state.depthFunc) {
+ state.depthFunc = depthFunc;
+ f->glDepthFunc(depthFunc);
+ }
+
+ const bool stencilTest = psD->m_stencilTest;
+ const GLuint stencilReadMask = psD->m_stencilReadMask;
+ const GLuint stencilWriteMask = psD->m_stencilWriteMask;
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace stencilFront = {
+ toGlCompareOp(psD->m_stencilFront.compareOp),
+ toGlStencilOp(psD->m_stencilFront.failOp),
+ toGlStencilOp(psD->m_stencilFront.depthFailOp),
+ toGlStencilOp(psD->m_stencilFront.passOp)
+ };
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace stencilBack = {
+ toGlCompareOp(psD->m_stencilBack.compareOp),
+ toGlStencilOp(psD->m_stencilBack.failOp),
+ toGlStencilOp(psD->m_stencilBack.depthFailOp),
+ toGlStencilOp(psD->m_stencilBack.passOp)
+ };
+ if (forceUpdate || stencilTest != state.stencilTest
+ || (stencilTest
+ && (stencilReadMask != state.stencilReadMask || stencilWriteMask != state.stencilWriteMask
+ || stencilFront != state.stencil[0] || stencilBack != state.stencil[1])))
+ {
+ state.stencilTest = stencilTest;
+ if (stencilTest) {
+ state.stencilReadMask = stencilReadMask;
+ state.stencilWriteMask = stencilWriteMask;
+ state.stencil[0] = stencilFront;
+ state.stencil[1] = stencilBack;
+
+ f->glEnable(GL_STENCIL_TEST);
+
+ f->glStencilFuncSeparate(GL_FRONT, stencilFront.func, state.dynamic.stencilRef, stencilReadMask);
+ f->glStencilOpSeparate(GL_FRONT, stencilFront.failOp, stencilFront.zfailOp, stencilFront.zpassOp);
+ f->glStencilMaskSeparate(GL_FRONT, stencilWriteMask);
+
+ f->glStencilFuncSeparate(GL_BACK, stencilBack.func, state.dynamic.stencilRef, stencilReadMask);
+ f->glStencilOpSeparate(GL_BACK, stencilBack.failOp, stencilBack.zfailOp, stencilBack.zpassOp);
+ f->glStencilMaskSeparate(GL_BACK, stencilWriteMask);
+ } else {
+ f->glDisable(GL_STENCIL_TEST);
+ }
}
- if (psD->m_topology == QRhiGraphicsPipeline::Lines || psD->m_topology == QRhiGraphicsPipeline::LineStrip)
- f->glLineWidth(psD->m_lineWidth);
+ const bool polyOffsetFill = psD->m_depthBias != 0 || !qFuzzyIsNull(psD->m_slopeScaledDepthBias);
+ const float polyOffsetFactor = psD->m_slopeScaledDepthBias;
+ const float polyOffsetUnits = psD->m_depthBias;
+ if (forceUpdate || state.polyOffsetFill != polyOffsetFill
+ || polyOffsetFactor != state.polyOffsetFactor || polyOffsetUnits != state.polyOffsetUnits)
+ {
+ state.polyOffsetFill = polyOffsetFill;
+ state.polyOffsetFactor = polyOffsetFactor;
+ state.polyOffsetUnits = polyOffsetUnits;
+ if (polyOffsetFill) {
+ f->glPolygonOffset(polyOffsetFactor, polyOffsetUnits);
+ f->glEnable(GL_POLYGON_OFFSET_FILL);
+ } else {
+ f->glDisable(GL_POLYGON_OFFSET_FILL);
+ }
+ }
+
+ if (psD->m_topology == QRhiGraphicsPipeline::Lines || psD->m_topology == QRhiGraphicsPipeline::LineStrip) {
+ const float lineWidth = psD->m_lineWidth;
+ if (forceUpdate || lineWidth != state.lineWidth) {
+ state.lineWidth = lineWidth;
+ f->glLineWidth(lineWidth);
+ }
+ }
f->glUseProgram(psD->program);
}
@@ -2825,8 +2946,6 @@ void QRhiGles2::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
cbD->recordingPass = QGles2CommandBuffer::ComputePass;
cbD->resetCachedState();
-
- cbD->computePassState.reset();
}
void QRhiGles2::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -3135,11 +3254,12 @@ void QRhiGles2::gatherUniforms(GLuint program,
QByteArray prefix = ub.structName.toUtf8() + '.';
for (const QShaderDescription::BlockVariable &blockMember : ub.members) {
if (blockMember.type == QShaderDescription::Struct) {
- prefix += blockMember.name.toUtf8();
+ QByteArray structPrefix = prefix + blockMember.name.toUtf8();
+
const int baseOffset = blockMember.offset;
if (blockMember.arrayDims.isEmpty()) {
for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
- registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst);
+ registerUniformIfActive(structMember, structPrefix, ub.binding, baseOffset, program, dst);
} else {
if (blockMember.arrayDims.count() > 1) {
qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.",
@@ -3149,7 +3269,7 @@ void QRhiGles2::gatherUniforms(GLuint program,
const int elemSize = blockMember.size / dim;
int elemOffset = baseOffset;
for (int di = 0; di < dim; ++di) {
- const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.';
+ const QByteArray arrayPrefix = structPrefix + '[' + QByteArray::number(di) + ']' + '.';
for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst);
elemOffset += elemSize;
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index 8b7d01532a..ac7b384cb6 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -522,6 +522,45 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
QRhiShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
+ struct GraphicsPassState {
+ bool valid = false;
+ bool scissor;
+ bool cullFace;
+ GLenum cullMode;
+ GLenum frontFace;
+ bool blendEnabled;
+ struct ColorMask { bool r, g, b, a; } colorMask;
+ struct Blend {
+ GLenum srcColor;
+ GLenum dstColor;
+ GLenum srcAlpha;
+ GLenum dstAlpha;
+ GLenum opColor;
+ GLenum opAlpha;
+ } blend;
+ bool depthTest;
+ bool depthWrite;
+ GLenum depthFunc;
+ bool stencilTest;
+ GLuint stencilReadMask;
+ GLuint stencilWriteMask;
+ struct StencilFace {
+ GLenum func;
+ GLenum failOp;
+ GLenum zfailOp;
+ GLenum zpassOp;
+ } stencil[2]; // front, back
+ bool polyOffsetFill;
+ float polyOffsetFactor;
+ float polyOffsetUnits;
+ float lineWidth;
+ void reset() { valid = false; }
+ struct {
+ // not part of QRhiGraphicsPipeline but used by setGraphicsPipeline()
+ GLint stencilRef = 0;
+ } dynamic;
+ } graphicsPassState;
+
struct ComputePassState {
enum Access {
Read = 0x01,
@@ -566,11 +605,57 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
currentGraphicsSrb = nullptr;
currentComputeSrb = nullptr;
currentSrbGeneration = 0;
+ graphicsPassState.reset();
+ computePassState.reset();
}
};
Q_DECLARE_TYPEINFO(QGles2CommandBuffer::Command, Q_MOVABLE_TYPE);
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
+{
+ return a.func == b.func
+ && a.failOp == b.failOp
+ && a.zfailOp == b.zfailOp
+ && a.zpassOp == b.zpassOp;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
+{
+ return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
+ const QGles2CommandBuffer::GraphicsPassState::Blend &b)
+{
+ return a.srcColor == b.srcColor
+ && a.dstColor == b.dstColor
+ && a.srcAlpha == b.srcAlpha
+ && a.dstAlpha == b.dstAlpha
+ && a.opColor == b.opColor
+ && a.opAlpha == b.opAlpha;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
+ const QGles2CommandBuffer::GraphicsPassState::Blend &b)
+{
+ return !(a == b);
+}
+
struct QGles2SwapChain : public QRhiSwapChain
{
QGles2SwapChain(QRhiImplementation *rhi);
@@ -709,7 +794,7 @@ public:
QRhiPassResourceTracker::TextureAccess access,
QRhiPassResourceTracker::TextureStage stage);
void executeCommandBuffer(QRhiCommandBuffer *cb);
- void executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps);
+ void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD);
void bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
QRhiShaderResourceBindings *srb,
const uint *dynOfsPairs, int dynOfsCount);
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 70cc20cbe6..32fbd8cfed 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -2120,7 +2120,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const
return true;
}
-/* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.
+/* Implement alphaMapForGlyph() which is called by QPA Windows code.
* Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp
index 61eed3fff1..ede4ccd482 100644
--- a/src/gui/util/qvalidator.cpp
+++ b/src/gui/util/qvalidator.cpp
@@ -363,8 +363,9 @@ QIntValidator::~QIntValidator()
\fn QValidator::State QIntValidator::validate(QString &input, int &pos) const
Returns \l Acceptable if the \a input is an integer within the
- valid range, \l Intermediate if the \a input is a prefix of an integer in the
- valid range, and \l Invalid otherwise.
+ valid range. If \a input has at most as many digits as the top of the range,
+ or is a prefix of an integer in the valid range, returns \l Intermediate.
+ Otherwise, returns \l Invalid.
If the valid range consists of just positive integers (e.g., 32 to 100)
and \a input is a negative integer, then Invalid is returned. (On the other
@@ -373,6 +374,10 @@ QIntValidator::~QIntValidator()
the user might be just about to type the minus (especially for right-to-left
languages).
+ Similarly, if the valid range is between 46 and 53, then 41 and 59 will be
+ evaluated as \l Intermediate, as otherwise the user wouldn't be able to
+ change a value from 49 to 51.
+
\snippet code/src_gui_util_qvalidator.cpp 2
By default, the \a pos parameter is not used by this validator.