Merge remote-tracking branch 'origin/5.14' into 5.15

Change-Id: I77ba01f09b3dbcaf13cb265a70d9da661c32a61f
This commit is contained in:
Qt Forward Merge Bot 2019-10-01 01:01:20 +02:00
commit 4e40c54a3c
72 changed files with 5384 additions and 3914 deletions

View File

@ -484,6 +484,17 @@
]
}
},
"signaling_nan": {
"label": "Signaling NaN for doubles",
"type": "compile",
"test": {
"head": [ "#include <limits>" ],
"main": [
"using B = std::numeric_limits<double>;",
"static_assert(B::has_signaling_NaN, \"System lacks signaling NaN\");"
]
}
},
"sse2": {
"label": "SSE2 instructions",
"type": "x86Simd"
@ -1005,6 +1016,11 @@
{ "type": "define", "name": "QT_REDUCE_RELOCATIONS" }
]
},
"signaling_nan": {
"label": "Signaling NaN",
"condition": "tests.signaling_nan",
"output": [ "publicFeature" ]
},
"sse2": {
"label": "SSE2",
"condition": "(arch.i386 || arch.x86_64) && tests.sse2",

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -64,7 +64,7 @@ int main(int argc, char *argv[])
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -128,7 +128,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION
QString translatorFileName = QLatin1String("qt_");
QString translatorFileName = QLatin1String("qtbase_");
translatorFileName += QLocale::system().name();
QTranslator *translator = new QTranslator(&app);
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))

View File

@ -0,0 +1,41 @@
#
# qmake configuration for the NXP i.MX8 based boards (64-bit)
#
# The configuration below is set up for running with the fbdev-style
# Vivante graphics stack. (so eglfs with the eglfs_viv backend, no
# direct drm use via eglfs_kms)
# Wayland should also be functional. However, when writing Wayland
# *compositors* with Qt, the eglfs backend will have to be switched to
# eglfs_viv_wl by setting the QT_QPA_EGLFS_INTEGRATION environment
# variable.
#
# Below is an example configure line that assumes there is an AArch64
# toolchain and sysroot available in $HOME/imx8. On device Qt is
# expected to be placed under /usr/local/qt514 whereas on the host
# 'make install' will copy the host tools and the target libraries to
# $HOME/imx8/qt5.
#
# ./configure -release -opengl es2 -device linux-imx8-g++ \
# -device-option CROSS_COMPILE=~/imx8/toolchain/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux- \
# -sysroot ~/imx8/sysroot \
# -opensource -confirm-license -make libs -prefix /usr/local/qt514 -extprefix ~/imx8/qt5 -v
include(../common/linux_device_pre.conf)
QMAKE_LIBS_EGL += -lEGL
QMAKE_LIBS_OPENGL_ES2 += -lGLESv2 -lEGL -lGAL
QMAKE_LIBS_OPENVG += -lOpenVG -lEGL -lGAL
IMX8_CFLAGS = -march=armv8-a -mtune=cortex-a72.cortex-a53 -DLINUX=1 -DEGL_API_FB=1
QMAKE_CFLAGS += $$IMX8_CFLAGS
QMAKE_CXXFLAGS += $$IMX8_CFLAGS
DISTRO_OPTS += aarch64
# Preferred eglfs backend
EGLFS_DEVICE_INTEGRATION = eglfs_viv
include(../common/linux_arm_device_post.conf)
load(qt_config)

View File

@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the qmake spec of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../../linux-g++/qplatformdefs.h"

View File

@ -992,6 +992,22 @@
\row \li embed_translations \li Embed the generated translations from
\c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
Requires \c lrelease to be set, too. Not set by default.
\row \li create_libtool \li Create a libtool .la file for the currently
built library.
\row \li create_pc \li Create a pkg-config .pc file for the currently built
library.
\row \li no_batch \li NMake only: Turn off generation of NMake batch rules
or inference rules.
\row \li skip_target_version_ext \li Suppress the automatic version number
appended to the DLL file name on Windows.
\row \li suppress_vcproj_warnings \li Suppress warnings of the VS project
generator.
\row \li windeployqt \li Automatically invoke windeployqt after linking,
and add the output as deployment items.
\row \li dont_recurse \li Suppress qmake recursion for the current
subproject.
\row \li no_include_pwd \li Do not add the current directory to
INCLUDEPATHS.
\endtable
When you use the \c debug_and_release option (which is the default under
@ -1039,6 +1055,8 @@
qmake will process all libraries linked to
by the application and find their meta-information (see
\l{LibDepend}{Library Dependencies} for more info).
\row \li no_install_prl \li This option disables the generation of
installation rules for generated .prl files.
\endtable
\note The \c create_prl option is required when \e {building} a

View File

@ -0,0 +1,42 @@
From 3442a3ce9c2bd366eb0bd1c18d37a6ce732a888d Mon Sep 17 00:00:00 2001
From: Andy Shaw <andy.shaw@qt.io>
Date: Wed, 25 Sep 2019 09:17:01 +0200
Subject: [PATCH] Fix CVE-2019-16168 in SQLite
v3.29.0 is the latest and there is no indication as to when the next
release is so we will apply this separately for now and it can be
reverted once it is in a release that we ship with.
This patch is taken from https://www.sqlite.org/src/info/98357d8c1263920b
Change-Id: I82d398b093b67842a4369e3220c01e7eea30763a
---
src/3rdparty/sqlite/sqlite3.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 61bfdeb766..b3e6ae27b6 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -105933,7 +105933,9 @@ static void decodeIntArray(
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ int sz = sqlite3Atoi(z+3);
+ if( sz<2 ) sz = 2;
+ pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
}
@@ -143260,6 +143262,7 @@ static int whereLoopAddBtreeIndex(
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
+ assert( pSrc->pTab->szTabRow>0 );
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
--
2.20.1 (Apple Git-117)

View File

@ -6,8 +6,8 @@
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "https://www.sqlite.org/",
"Version": "3.28.0",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3280000.zip",
"Version": "3.29.0",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3290000.zip",
"License": "Public Domain",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
}

File diff suppressed because it is too large Load Diff

View File

@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.28.0"
#define SQLITE_VERSION_NUMBER 3028000
#define SQLITE_SOURCE_ID "2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f83156b50"
#define SQLITE_VERSION "3.29.0"
#define SQLITE_VERSION_NUMBER 3029000
#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -1296,8 +1296,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
** to test whether a file is at least readable. The file can be a
** directory.
** to test whether a file is at least readable. The SQLITE_ACCESS_READ
** flag is never actually used and is not implemented in the built-in
** VFSes of SQLite. The file is named by the second argument and can be a
** directory. The xAccess method returns [SQLITE_OK] on success or some
** non-zero error code if there is an I/O error or if the name of
** the file given in the second argument is illegal. If SQLITE_OK
** is returned, then non-zero or zero is written into *pResOut to indicate
** whether or not the file is accessible.
**
** ^SQLite will always allocate at least mxPathname+1 bytes for the
** output buffer xFullPathname. The exact size of the output buffer
@ -2198,6 +2204,7 @@ struct sqlite3_mem_methods {
** features include but are not limited to the following:
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@ -2213,6 +2220,34 @@ struct sqlite3_mem_methods {
** integer into which is written 0 or 1 to indicate whether the writable_schema
** is enabled or disabled following this call.
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
** the legacy behavior of the [ALTER TABLE RENAME] command such it
** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
** additional information. This feature can also be turned on and off
** using the [PRAGMA legacy_alter_table] statement.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statement
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@ -2227,7 +2262,10 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */
#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */
#define SQLITE_DBCONFIG_MAX 1011 /* Largest DBCONFIG */
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@ -7319,7 +7357,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking

View File

@ -416,7 +416,7 @@ public:
LoadArchiveMemberHint = 0x04
};
Q_DECLARE_FLAGS(LoadHints, LoadHint)
Q_FLAG(LoadHints)
Q_FLAG(LoadHint)
...
}
//! [39]

View File

@ -109,6 +109,7 @@
# define QT_FEATURE_renameat2 -1
#endif
#define QT_FEATURE_sharedmemory -1
#define QT_FEATURE_signaling_nan -1
#define QT_FEATURE_slog2 -1
#ifdef __GLIBC_PREREQ
# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)

View File

@ -81,11 +81,13 @@ Q_CORE_EXPORT bool qIsNaN(float f) { return qt_is_nan(f); }
*/
Q_CORE_EXPORT bool qIsFinite(float f) { return qt_is_finite(f); }
#if QT_CONFIG(signaling_nan)
/*!
Returns the bit pattern of a signalling NaN as a double.
\relates <QtGlobal>
*/
Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
#endif
/*!
Returns the bit pattern of a quiet NaN as a double.

View File

@ -44,7 +44,6 @@
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
@ -53,7 +52,9 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
#if QT_CONFIG(signaling_nan)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
#endif
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
@ -61,7 +62,9 @@ Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
#define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
#define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
#if QT_CONFIG(signaling_nan)
# define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
#endif
#define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
QT_END_NAMESPACE

View File

@ -133,13 +133,14 @@ Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
return std::numeric_limits<double>::infinity();
}
// Signaling NaN
#if QT_CONFIG(signaling_nan)
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
{
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
"platform has no definition for signaling NaN for type double");
return std::numeric_limits<double>::signaling_NaN();
}
#endif
// Quiet NaN
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept

View File

@ -90,47 +90,6 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
QT_BEGIN_NAMESPACE
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
static qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept;
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# else
# define _rdrandXX_step _rdrand32_step
# endif
static QT_FUNCTION_TARGET(RDRND) qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
int retries = 10;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
else if (--retries == 0)
goto out;
}
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
bool ok = _rdrand32_step(ptr);
if (!ok && --retries)
continue;
if (ok)
++ptr;
break;
}
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
#else
static qsizetype qt_random_cpu(void *, qsizetype)
{
return 0;
}
#endif
enum {
// may be "overridden" by a member enum
FillBufferNoexcept = true
@ -371,8 +330,8 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin,
}
qsizetype filled = 0;
if (qt_has_hwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
filled += qt_random_cpu(buffer, count);
if (qHasHwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
filled += qRandomCpu(buffer, count);
if (filled != count && (uint(qt_randomdevice_control.loadAcquire()) & SkipSystemRNG) == 0) {
qsizetype bytesFilled =

View File

@ -81,14 +81,6 @@ static const struct {
} qt_randomdevice_control;
#endif
inline bool qt_has_hwrng()
{
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
return qCpuHasFeature(RDRND);
#else
return false;
#endif
}
QT_END_NAMESPACE

View File

@ -249,16 +249,18 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
isSymLink(). The symLinkTarget() function provides the name of the file
the symlink points to.
On Unix (including \macos and iOS), the symlink has the same size() has
the file it points to, because Unix handles symlinks
transparently; similarly, opening a symlink using QFile
effectively opens the link's target. For example:
On Unix (including \macos and iOS), the property getter functions in this
class return the properties such as times and size of the target file, not
the symlink, because Unix handles symlinks transparently. Opening a symlink
using QFile effectively opens the link's target. For example:
\snippet code/src_corelib_io_qfileinfo.cpp 0
On Windows, shortcuts are \c .lnk files. The reported size() is that of
the shortcut (not the link's target), and opening a shortcut using QFile
opens the \c .lnk file. For example:
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
on Unix systems, the property getters return the size of the targeted file,
not the \c .lnk file itself. This behavior is deprecated and will likely be
removed in a future version of Qt, after which \c .lnk files will be treated
as regular files.
\snippet code/src_corelib_io_qfileinfo.cpp 1
@ -903,6 +905,9 @@ QDir QFileInfo::absoluteDir() const
/*!
Returns \c true if the user can read the file; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
readable (not the symlink).
\note If the \l{NTFS permissions} check has not been enabled, the result
on Windows will merely reflect whether the file exists.
@ -920,6 +925,9 @@ bool QFileInfo::isReadable() const
/*!
Returns \c true if the user can write to the file; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
writeable (not the symlink).
\note If the \l{NTFS permissions} check has not been enabled, the result on
Windows will merely reflect whether the file is marked as Read Only.
@ -937,6 +945,9 @@ bool QFileInfo::isWritable() const
/*!
Returns \c true if the file is executable; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is
executable (not the symlink).
\sa isReadable(), isWritable(), permission()
*/
bool QFileInfo::isExecutable() const
@ -951,8 +962,13 @@ bool QFileInfo::isExecutable() const
/*!
Returns \c true if this is a `hidden' file; otherwise returns \c false.
\b{Note:} This function returns \c true for the special entries
"." and ".." on Unix, even though QDir::entryList threats them as shown.
\b{Note:} This function returns \c true for the special entries "." and
".." on Unix, even though QDir::entryList threats them as shown. And note
that, since this function inspects the file name, on Unix it will inspect
the name of the symlink, if this file is a symlink, not the target's name.
On Windows, this function returns \c true if the target file is hidden (not
the symlink).
*/
bool QFileInfo::isHidden() const
{
@ -991,6 +1007,9 @@ bool QFileInfo::isNativePath() const
link to a file. Returns \c false if the
object points to something which isn't a file, such as a directory.
If the file is a symlink, this function returns true if the target is a
regular file (not the symlink).
\sa isDir(), isSymLink(), isBundle()
*/
bool QFileInfo::isFile() const
@ -1006,6 +1025,9 @@ bool QFileInfo::isFile() const
Returns \c true if this object points to a directory or to a symbolic
link to a directory; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is a
directory (not the symlink).
\sa isFile(), isSymLink(), isBundle()
*/
bool QFileInfo::isDir() const
@ -1023,6 +1045,9 @@ bool QFileInfo::isDir() const
Returns \c true if this object points to a bundle or to a symbolic
link to a bundle on \macos and iOS; otherwise returns \c false.
If the file is a symlink, this function returns true if the target is a
bundle (not the symlink).
\sa isDir(), isSymLink(), isFile()
*/
bool QFileInfo::isBundle() const
@ -1044,7 +1069,8 @@ bool QFileInfo::isBundle() const
the \l{symLinkTarget()}{link's target}.
In addition, true will be returned for shortcuts (\c *.lnk files) on
Windows. Opening those will open the \c .lnk file itself.
Windows. This behavior is deprecated and will likely change in a future
version of Qt. Opening those will open the \c .lnk file itself.
Example:
@ -1190,6 +1216,9 @@ QString QFileInfo::symLinkTarget() const
milliseconds). On Windows, it will return an empty string unless
the \l{NTFS permissions} check has been enabled.
If the file is a symlink, this function returns the owner of the target
(not the symlink).
\sa ownerId(), group(), groupId()
*/
QString QFileInfo::owner() const
@ -1206,6 +1235,9 @@ QString QFileInfo::owner() const
On Windows and on systems where files do not have owners this
function returns ((uint) -2).
If the file is a symlink, this function returns the id of the owner of the target
(not the symlink).
\sa owner(), group(), groupId()
*/
uint QFileInfo::ownerId() const
@ -1225,6 +1257,9 @@ uint QFileInfo::ownerId() const
This function can be time consuming under Unix (in the order of
milliseconds).
If the file is a symlink, this function returns the owning group of the
target (not the symlink).
\sa groupId(), owner(), ownerId()
*/
QString QFileInfo::group() const
@ -1241,6 +1276,9 @@ QString QFileInfo::group() const
On Windows and on systems where files do not have groups this
function always returns (uint) -2.
If the file is a symlink, this function returns the id of the group owning the
target (not the symlink).
\sa group(), owner(), ownerId()
*/
uint QFileInfo::groupId() const
@ -1266,6 +1304,9 @@ uint QFileInfo::groupId() const
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 10
If the file is a symlink, this function checks the permissions of the
target (not the symlink).
\sa isReadable(), isWritable(), isExecutable()
*/
bool QFileInfo::permission(QFile::Permissions permissions) const
@ -1288,6 +1329,9 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
\note The result might be inaccurate on Windows if the
\l{NTFS permissions} check has not been enabled.
If the file is a symlink, this function returns the permissions of the
target (not the symlink).
*/
QFile::Permissions QFileInfo::permissions() const
{
@ -1305,6 +1349,9 @@ QFile::Permissions QFileInfo::permissions() const
Returns the file size in bytes. If the file does not exist or cannot be
fetched, 0 is returned.
If the file is a symlink, the size of the target file is returned
(not the symlink).
\sa exists()
*/
qint64 QFileInfo::size() const
@ -1334,6 +1381,9 @@ qint64 QFileInfo::size() const
the time the file was created, metadataChangeTime() to get the time its
metadata was last changed, or lastModified() to get the time it was last modified.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
*/
QDateTime QFileInfo::created() const
@ -1352,6 +1402,9 @@ QDateTime QFileInfo::created() const
If the file birth time is not available, this function returns an invalid
QDateTime.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa lastModified(), lastRead(), metadataChangeTime()
*/
QDateTime QFileInfo::birthTime() const
@ -1366,6 +1419,9 @@ QDateTime QFileInfo::birthTime() const
user writes or sets inode information (for example, changing the file
permissions).
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa lastModified(), lastRead()
*/
QDateTime QFileInfo::metadataChangeTime() const
@ -1376,6 +1432,9 @@ QDateTime QFileInfo::metadataChangeTime() const
/*!
Returns the date and local time when the file was last modified.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
*/
QDateTime QFileInfo::lastModified() const
@ -1389,6 +1448,9 @@ QDateTime QFileInfo::lastModified() const
On platforms where this information is not available, returns the
same as lastModified().
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
*/
QDateTime QFileInfo::lastRead() const
@ -1402,6 +1464,9 @@ QDateTime QFileInfo::lastRead() const
Returns the file time specified by \a time. If the time cannot be
determined, an invalid date time is returned.
If the file is a symlink, the time of the target file is returned
(not the symlink).
\sa QFile::FileTime, QDateTime::isValid()
*/
QDateTime QFileInfo::fileTime(QFile::FileTime time) const

View File

@ -69,7 +69,9 @@ static bool checkNameDecodable(const char *d_name, qsizetype len)
# ifdef QT_LOCALE_IS_UTF8
int mibEnum = 106;
# else
int mibEnum = codec->mibEnum();
int mibEnum = 4; // Latin 1
if (codec)
mibEnum = codec->mibEnum();
# endif
if (Q_LIKELY(mibEnum == 106)) // UTF-8
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;

View File

@ -423,7 +423,7 @@ bool QEventDispatcherCoreFoundation::processPostedEvents()
m_processEvents.processedPostedEvents = true;
qCDebug(lcEventDispatcher) << "Sending posted events for"
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
QCoreApplication::sendPostedEvents();
return true;

View File

@ -376,6 +376,38 @@ static quint64 detectProcessorFeatures()
features &= ~AllAVX512;
}
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
/**
* Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
* failing random generation instruction, which always returns
* 0xffffffff, even when generation was "successful".
*
* This code checks if hardware random generator generates four consecutive
* equal numbers. If it does, then we probably have a failing one and
* should disable it completely.
*
* https://bugreports.qt.io/browse/QTBUG-69423
*/
if (features & CpuFeatureRDRND) {
const qsizetype testBufferSize = 4;
unsigned testBuffer[4] = {};
const qsizetype generated = qRandomCpu(testBuffer, testBufferSize);
if (Q_UNLIKELY(generated == testBufferSize &&
testBuffer[0] == testBuffer[1] &&
testBuffer[1] == testBuffer[2] &&
testBuffer[2] == testBuffer[3])) {
fprintf(stderr, "WARNING: CPU random generator seem to be failing, disable hardware random number generation\n");
fprintf(stderr, "WARNING: RDRND generated: 0x%x 0x%x 0x%x 0x%x\n",
testBuffer[0], testBuffer[1], testBuffer[2], testBuffer[3]);
features &= ~CpuFeatureRDRND;
}
}
#endif
return features;
}
@ -590,4 +622,40 @@ void qDumpCPUFeatures()
puts("");
}
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# else
# define _rdrandXX_step _rdrand32_step
# endif
QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
int retries = 10;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
else if (--retries == 0)
goto out;
}
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
bool ok = _rdrand32_step(ptr);
if (!ok && --retries)
continue;
if (ok)
++ptr;
break;
}
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
#endif
QT_END_NAMESPACE

View File

@ -346,6 +346,15 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
#endif
Q_CORE_EXPORT quint64 qDetectCpuFeatures();
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept;
#else
static inline qsizetype qRandomCpu(void *, qsizetype) noexcept
{
return 0;
}
#endif
static inline quint64 qCpuFeatures()
{
quint64 features = qt_cpu_features[0].loadRelaxed();
@ -362,6 +371,15 @@ static inline quint64 qCpuFeatures()
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
inline bool qHasHwrng()
{
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
return qCpuHasFeature(RDRND);
#else
return false;
#endif
}
#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)

View File

@ -104,7 +104,7 @@ public:
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
resize(list.size());
resize(int(list.size())); // ### q6sizetype
std::copy(list.begin(), list.end(),
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
return *this;

View File

@ -44,6 +44,7 @@
#include <QStandardPaths>
#include <QDir>
#include <QSaveFile>
#include <QCoreApplication>
#include <QLoggingCategory>
#include <QCryptographicHash>
@ -54,7 +55,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
#ifndef GL_CONTEXT_LOST
#define GL_CONTEXT_LOST 0x0507
@ -64,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#endif
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#endif
const quint32 BINSHADER_MAGIC = 0x5174;
const quint32 BINSHADER_VERSION = 0x3;
const quint32 BINSHADER_QTVERSION = QT_VERSION;
@ -123,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
}
qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
@ -154,24 +159,24 @@ static inline QByteArray readStr(const uchar **p)
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
{
if (buf.size() < BASE_HEADER_SIZE) {
qCDebug(DBG_SHADER_CACHE, "Cached size too small");
qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
return false;
}
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
if (readUInt(&p) != BINSHADER_MAGIC) {
qCDebug(DBG_SHADER_CACHE, "Magic does not match");
qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
return false;
}
if (readUInt(&p) != BINSHADER_VERSION) {
qCDebug(DBG_SHADER_CACHE, "Version does not match");
qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
return false;
}
if (readUInt(&p) != BINSHADER_QTVERSION) {
qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
return false;
}
if (readUInt(&p) != sizeof(quintptr)) {
qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
return false;
}
return true;
@ -196,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLenum err = funcs->glGetError();
if (err != GL_NO_ERROR) {
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return false;
@ -204,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLint linkStatus = 0;
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
programId, blobSize, blobFormat, linkStatus, err);
return false;
}
qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
qCDebug(lcOpenGLProgramDiskCache, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return true;
}
@ -318,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
if (vendor != info.glvendor) {
// readStr returns non-null terminated strings just pointing to inside
// 'p' so must print these via the stream qCDebug and not constData().
qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
qCDebug(lcOpenGLProgramDiskCache) << "GL_VENDOR does not match" << vendor << info.glvendor;
undertaker.setActive();
return false;
}
QByteArray renderer = readStr(&p);
if (renderer != info.glrenderer) {
qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
qCDebug(lcOpenGLProgramDiskCache) << "GL_RENDERER does not match" << renderer << info.glrenderer;
undertaker.setActive();
return false;
}
QByteArray version = readStr(&p);
if (version != info.glversion) {
qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
qCDebug(lcOpenGLProgramDiskCache) << "GL_VERSION does not match" << version << info.glversion;
undertaker.setActive();
return false;
}
@ -383,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
const int totalSize = headerSize + paddingSize + blobSize;
qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
qCDebug(lcOpenGLProgramDiskCache, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
if (!blobSize)
return;
@ -417,7 +422,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
#endif
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
if (blobSize != outSize) {
qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
qCDebug(lcOpenGLProgramDiskCache, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
return;
}
@ -433,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(blob) < blob.length())
#endif
qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
} else {
qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
}
}
@ -452,4 +457,45 @@ void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *conte
}
#endif
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
: QOpenGLSharedResource(context->shareGroup()),
m_supported(false)
{
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via app attribute");
return;
}
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via env var");
return;
}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
if (ctx->isOpenGLES()) {
qCDebug(lcOpenGLProgramDiskCache, "OpenGL ES v%d context", ctx->format().majorVersion());
if (ctx->format().majorVersion() >= 3) {
m_supported = true;
} else {
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
qCDebug(lcOpenGLProgramDiskCache, "GL_OES_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
} else {
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
qCDebug(lcOpenGLProgramDiskCache, "GL_ARB_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
if (m_supported) {
GLint fmtCount = 0;
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
qCDebug(lcOpenGLProgramDiskCache, "Supported binary format count = %d", fmtCount);
m_supported = fmtCount > 0;
}
}
qCDebug(lcOpenGLProgramDiskCache, "Shader cache supported = %d", m_supported);
}
QT_END_NAMESPACE

View File

@ -52,21 +52,26 @@
//
#include <QtGui/qtguiglobal.h>
#include <QtGui/qopenglshaderprogram.h>
#include <QtCore/qcache.h>
#include <QtCore/qmutex.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/private/qshader_p.h>
QT_BEGIN_NAMESPACE
// These classes are also used by the OpenGL backend of QRhi. They must
// therefore stay independent from QOpenGLShader(Program). Must rely only on
// QOpenGLContext/Functions.
class QOpenGLProgramBinaryCache
{
public:
struct ShaderDesc {
ShaderDesc() { }
ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
: type(type), source(source)
ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
: stage(stage), source(source)
{ }
QOpenGLShader::ShaderType type;
QShader::Stage stage;
QByteArray source;
};
struct ProgramDesc {
@ -104,6 +109,36 @@ private:
QMutex m_mutex;
};
// While unlikely, one application can in theory use contexts with different versions
// or profiles. Therefore any version- or extension-specific checks must be done on a
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
// although it's once-per-sharing-context-group, not per-context. Still, this should
// be good enough in practice.
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
{
public:
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
void invalidateResource() override { }
void freeResource(QOpenGLContext *) override { }
bool isSupported() const { return m_supported; }
private:
bool m_supported;
};
class QOpenGLProgramBinarySupportCheckWrapper
{
public:
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
{
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
}
private:
QOpenGLMultiGroupSharedResource m_resource;
};
QT_END_NAMESPACE
#endif

View File

@ -47,7 +47,6 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
@ -178,7 +177,7 @@ QT_BEGIN_NAMESPACE
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
// For GLES 3.1/3.2
#ifndef GL_GEOMETRY_SHADER
@ -209,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#endif
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#endif
#ifndef QT_OPENGL_ES_2
static inline bool isFormatGLES(const QSurfaceFormat &f)
{
@ -1080,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
return addCacheableShaderFromSourceCode(type, QByteArray(source));
}
static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
{
switch (type) {
case QOpenGLShader::Vertex:
return QShader::VertexStage;
case QOpenGLShader::Fragment:
return QShader::FragmentStage;
case QOpenGLShader::Geometry:
return QShader::GeometryStage;
case QOpenGLShader::TessellationControl:
return QShader::TessellationControlStage;
case QOpenGLShader::TessellationEvaluation:
return QShader::TessellationEvaluationStage;
case QOpenGLShader::Compute:
return QShader::ComputeStage;
}
return QShader::VertexStage;
}
static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
{
switch (stage) {
case QShader::VertexStage:
return QOpenGLShader::Vertex;
case QShader::TessellationControlStage:
return QOpenGLShader::TessellationControl;
case QShader::TessellationEvaluationStage:
return QOpenGLShader::TessellationEvaluation;
case QShader::GeometryStage:
return QOpenGLShader::Geometry;
case QShader::FragmentStage:
return QOpenGLShader::Fragment;
case QShader::ComputeStage:
return QOpenGLShader::Compute;
}
return QOpenGLShader::Vertex;
}
/*!
\overload
@ -1108,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
return true;
}
@ -1165,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceFile(type, fileName);
QOpenGLProgramBinaryCache::ShaderDesc shader(type);
QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
// NB! It could be tempting to defer reading the file contents and just
// hash the filename as the cache key, perhaps combined with last-modified
// timestamp checks. However, this would raise a number of issues (no
@ -3719,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
return true;
}
// While unlikely, one application can in theory use contexts with different versions
// or profiles. Therefore any version- or extension-specific checks must be done on a
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
// although it's once-per-sharing-context-group, not per-context. Still, this should
// be good enough in practice.
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
{
public:
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
void invalidateResource() override { }
void freeResource(QOpenGLContext *) override { }
bool isSupported() const { return m_supported; }
private:
bool m_supported;
};
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
: QOpenGLSharedResource(context->shareGroup()),
m_supported(false)
{
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
return;
}
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
return;
}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
if (ctx->isOpenGLES()) {
qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
if (ctx->format().majorVersion() >= 3) {
m_supported = true;
} else {
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
} else {
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
if (hasExt)
m_supported = true;
}
if (m_supported) {
GLint fmtCount = 0;
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
m_supported = fmtCount > 0;
}
}
qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
}
class QOpenGLProgramBinarySupportCheckWrapper
{
public:
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
{
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
}
private:
QOpenGLMultiGroupSharedResource m_resource;
};
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
@ -3800,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
{
Q_Q(QOpenGLShaderProgram);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
if (!s->compileSourceCode(shader.source)) {
log = s->log();
return false;
@ -3819,19 +3781,19 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
Q_Q(QOpenGLShaderProgram);
const QByteArray cacheKey = binaryProgram.cacheKey();
if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
binaryProgram.shaders.count(), cacheKey.constData());
bool needsCompile = true;
if (binCache.load(cacheKey, q->programId())) {
qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
needsCompile = false;
}
bool needsSave = false;
if (needsCompile) {
qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
if (compileCacheable())
needsSave = true;
else

View File

@ -34,7 +34,21 @@
**
****************************************************************************/
#include <qglobal.h>
#ifndef CS_TDR_P_H
#define CS_TDR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qglobal.h>
#ifdef Q_OS_WIN
@ -207,3 +221,5 @@ const BYTE g_killDeviceByTimingOut[] =
};
#endif // Q_OS_WIN
#endif // CS_TDR_P_H

View File

@ -1981,6 +1981,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const
How the renderbuffer is implemented by a backend is not exposed to the
applications. In some cases it may be backed by ordinary textures, while in
others there may be a different kind of native resource used.
Renderbuffers that are used as (and are only used as) depth-stencil buffers
in combination with a QRhiSwapChain's color buffers should have the
UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
depending on the backend and the underlying APIs, be more efficient, and
QRhi provides automatic sizing behavior to match the color buffers, which
means calling setPixelSize() and build() are not necessary for such
renderbuffers.
*/
/*!
@ -1996,12 +2004,15 @@ QRhiResource::Type QRhiBuffer::resourceType() const
Flag values for flags() and setFlags()
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
that the renderbuffer is only used in combination with a QRhiSwapChain and
never in other ways. Relevant with some backends, while others ignore it.
With OpenGL where a separate windowing system interface API is in use (EGL,
GLX, etc.), the flag is important since it avoids creating any actual
resource as there is already a windowing system provided depth/stencil
buffer as requested by QSurfaceFormat.
that the renderbuffer is only used in combination with a QRhiSwapChain, and
never in any other way. This provides automatic sizing and resource
rebuilding, so calling setPixelSize() or build() is not needed whenever
this flag is set. This flag value may also trigger backend-specific
behavior, for example with OpenGL, where a separate windowing system
interface API is in use (EGL, GLX, etc.), the flag is especially important
as it avoids creating any actual renderbuffer resource as there is already
a windowing system provided depth/stencil buffer as requested by
QSurfaceFormat.
*/
/*!
@ -2523,16 +2534,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
be used with the same pipeline, assuming the pipeline was built with one of
them in the first place.
Creating and then using a new \c srb2 that is very similar to \c srb with
the exception of referencing another texture could be implemented like the
following:
\badcode
srb2 = rhi->newShaderResourceBindings();
QVector<QRhiShaderResourceBinding> bindings = srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler);
srb2->setBindings(bindings);
srb2->build();
...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(srb2); // binds srb2
@ -2634,43 +2637,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
: d(new QRhiShaderResourceBindingPrivate)
{
}
/*!
\internal
*/
void QRhiShaderResourceBinding::detach()
{
qAtomicDetach(d);
}
/*!
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other)
: d(other.d)
{
d->ref.ref();
}
/*!
\internal
*/
QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other)
{
qAtomicAssign(d, other.d);
return *this;
}
/*!
Destructor.
*/
QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
{
if (!d->ref.deref())
delete d;
// Zero out everything, including possible padding, because will use
// qHashBits on it.
memset(&d.u, 0, sizeof(d.u));
}
/*!
@ -2687,8 +2657,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
*/
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
{
return (d == other.d)
|| (d->binding == other.d->binding && d->stage == other.d->stage && d->type == other.d->type);
return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
}
/*!
@ -2701,15 +2670,13 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = UniformBuffer;
d->u.ubuf.buf = buf;
d->u.ubuf.offset = 0;
d->u.ubuf.maybeSize = 0; // entire buffer
d->u.ubuf.hasDynamicOffset = false;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = UniformBuffer;
b.d.u.ubuf.buf = buf;
b.d.u.ubuf.offset = 0;
b.d.u.ubuf.maybeSize = 0; // entire buffer
b.d.u.ubuf.hasDynamicOffset = false;
return b;
}
@ -2730,9 +2697,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.ubuf.offset = offset;
d->u.ubuf.maybeSize = size;
b.d.u.ubuf.offset = offset;
b.d.u.ubuf.maybeSize = size;
return b;
}
@ -2751,8 +2717,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
int binding, StageFlags stage, QRhiBuffer *buf, int size)
{
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.ubuf.hasDynamicOffset = true;
b.d.u.ubuf.hasDynamicOffset = true;
return b;
}
@ -2765,13 +2730,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = SampledTexture;
d->u.stex.tex = tex;
d->u.stex.sampler = sampler;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = SampledTexture;
b.d.u.stex.tex = tex;
b.d.u.stex.sampler = sampler;
return b;
}
@ -2787,13 +2750,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = ImageLoad;
d->u.simage.tex = tex;
d->u.simage.level = level;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = ImageLoad;
b.d.u.simage.tex = tex;
b.d.u.simage.level = level;
return b;
}
@ -2809,8 +2770,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = ImageStore;
b.d.type = ImageStore;
return b;
}
@ -2826,8 +2786,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = ImageLoadStore;
b.d.type = ImageLoadStore;
return b;
}
@ -2841,14 +2800,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = BufferLoad;
d->u.sbuf.buf = buf;
d->u.sbuf.offset = 0;
d->u.sbuf.maybeSize = 0; // entire buffer
b.d.binding = binding;
b.d.stage = stage;
b.d.type = BufferLoad;
b.d.u.sbuf.buf = buf;
b.d.u.sbuf.offset = 0;
b.d.u.sbuf.maybeSize = 0; // entire buffer
return b;
}
@ -2864,9 +2821,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2880,8 +2836,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = BufferStore;
b.d.type = BufferStore;
return b;
}
@ -2897,9 +2852,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2913,8 +2867,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->type = BufferLoadStore;
b.d.type = BufferLoadStore;
return b;
}
@ -2930,9 +2883,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
d->u.sbuf.offset = offset;
d->u.sbuf.maybeSize = size;
b.d.u.sbuf.offset = offset;
b.d.u.sbuf.maybeSize = size;
return b;
}
@ -2948,28 +2900,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
*/
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
{
if (a.d == b.d)
const QRhiShaderResourceBinding::Data *da = a.data();
const QRhiShaderResourceBinding::Data *db = b.data();
if (da == db)
return true;
if (a.d->binding != b.d->binding
|| a.d->stage != b.d->stage
|| a.d->type != b.d->type)
if (da->binding != db->binding
|| da->stage != db->stage
|| da->type != db->type)
{
return false;
}
switch (a.d->type) {
switch (da->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (a.d->u.ubuf.buf != b.d->u.ubuf.buf
|| a.d->u.ubuf.offset != b.d->u.ubuf.offset
|| a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize)
if (da->u.ubuf.buf != db->u.ubuf.buf
|| da->u.ubuf.offset != db->u.ubuf.offset
|| da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
{
return false;
}
break;
case QRhiShaderResourceBinding::SampledTexture:
if (a.d->u.stex.tex != b.d->u.stex.tex
|| a.d->u.stex.sampler != b.d->u.stex.sampler)
if (da->u.stex.tex != db->u.stex.tex
|| da->u.stex.sampler != db->u.stex.sampler)
{
return false;
}
@ -2979,8 +2935,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::ImageStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
if (a.d->u.simage.tex != b.d->u.simage.tex
|| a.d->u.simage.level != b.d->u.simage.level)
if (da->u.simage.tex != db->u.simage.tex
|| da->u.simage.level != db->u.simage.level)
{
return false;
}
@ -2990,9 +2946,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::BufferStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
|| a.d->u.sbuf.offset != b.d->u.sbuf.offset
|| a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
if (da->u.sbuf.buf != db->u.sbuf.buf
|| da->u.sbuf.offset != db->u.sbuf.offset
|| da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
{
return false;
}
@ -3023,16 +2979,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
*/
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
{
const char *u = reinterpret_cast<const char *>(&b.d->u);
return seed + uint(b.d->binding) + 10 * uint(b.d->stage) + 100 * uint(b.d->type)
+ qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed);
const QRhiShaderResourceBinding::Data *d = b.data();
return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type)
+ qHashBits(&d->u, sizeof(d->u), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
{
const QRhiShaderResourceBindingPrivate *d = b.d;
QDebugStateSaver saver(dbg);
const QRhiShaderResourceBinding::Data *d = b.data();
dbg.nospace() << "QRhiShaderResourceBinding("
<< "binding=" << d->binding
<< " stage=" << d->stage
@ -3100,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVarLengthArray<QRhiShaderResourceBinding, 8> &bindings)
{
return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings);
}
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
{
QDebugStateSaver saver(dbg);
@ -3351,7 +3312,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
{
sc = rhi->newSwapChain();
ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(), // no need to set the size here due to UsedWithSwapChainOnly
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
sc->setWindow(window);
@ -3363,9 +3324,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
void resizeSwapChain()
{
const QSize outputSize = sc->surfacePixelSize();
ds->setPixelSize(outputSize);
ds->build();
hasSwapChain = sc->buildOrResize();
}
@ -3559,10 +3517,24 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
\return The size of the window's associated surface or layer. Do not assume
this is the same as QWindow::size() * QWindow::devicePixelRatio().
Can be called before buildOrResize() (but with window() already set), which
allows setting the correct size for the depth-stencil buffer that is then
used together with the swapchain's color buffers. Also used in combination
with currentPixelSize() to detect size changes.
\note Can also be called before buildOrResize(), if at least window() is
already set) This in combination with currentPixelSize() allows to detect
when a swapchain needs to be resized. However, watch out for the fact that
the size of the underlying native object (surface, layer, or similar) is
"live", so whenever this function is called, it returns the latest value
reported by the underlying implementation, without any atomicity guarantee.
Therefore, using this function to determine pixel sizes for graphics
resources that are used in a frame is strongly discouraged. Rely on
currentPixelSize() instead which returns a size that is atomic and will not
change between buildOrResize() invocations.
\note For depth-stencil buffers used in combination with the swapchain's
color buffers, it is strongly recommended to rely on the automatic sizing
and rebuilding behavior provided by the
QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
size via this function just to get a size that can be passed to
QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
atomicity as described above.
\sa currentPixelSize()
*/
@ -5541,7 +5513,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
const UsageState &state)
{
auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
auto it = m_buffers.find(buf);
if (it != m_buffers.end()) {
if (it->access != *access) {
const QByteArray name = buf->name();
@ -5557,12 +5529,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc
}
Buffer b;
b.buf = buf;
b.slot = slot;
b.access = *access;
b.stage = *stage;
b.stateAtPassBegin = state; // first use -> initial state
m_buffers.append(b);
m_buffers.insert(buf, b);
}
static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
@ -5581,7 +5552,7 @@ static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess acces
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
const UsageState &state)
{
auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
auto it = m_textures.find(tex);
if (it != m_textures.end()) {
if (it->access != *access) {
// Different subresources of a texture may be used for both load
@ -5605,11 +5576,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
}
Texture t;
t.tex = tex;
t.access = *access;
t.stage = *stage;
t.stateAtPassBegin = state; // first use -> initial state
m_textures.append(t);
m_textures.insert(tex, t);
}
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)

View File

@ -52,6 +52,7 @@
#include <QSize>
#include <QMatrix4x4>
#include <QVector>
#include <QVarLengthArray>
#include <QThread>
#include <QColor>
#include <QImage>
@ -320,10 +321,6 @@ public:
Q_DECLARE_FLAGS(StageFlags, StageFlag)
QRhiShaderResourceBinding();
QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
~QRhiShaderResourceBinding();
void detach();
bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
@ -344,19 +341,49 @@ public:
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
struct Data
{
int binding;
QRhiShaderResourceBinding::StageFlags stage;
QRhiShaderResourceBinding::Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
bool hasDynamicOffset;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
struct StorageImageData {
QRhiTexture *tex;
int level;
};
struct StorageBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
StorageImageData simage;
StorageBufferData sbuf;
} u;
};
Data *data() { return &d; }
const Data *data() const { return &d; }
private:
QRhiShaderResourceBindingPrivate *d;
friend class QRhiShaderResourceBindingPrivate;
friend Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
#endif
Data d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_MOVABLE_TYPE);
Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW;
@ -900,8 +927,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
public:
QRhiResource::Type resourceType() const override;
QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
template<typename InputIterator>
void setBindings(InputIterator first, InputIterator last)
{
m_bindings.clear();
std::copy(first, last, std::back_inserter(m_bindings));
}
void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed
{
setBindings(bindings.cbegin(), bindings.cend());
}
const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
@ -909,7 +950,7 @@ public:
protected:
QRhiShaderResourceBindings(QRhiImplementation *rhi);
QVector<QRhiShaderResourceBinding> m_bindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
#endif
@ -1040,8 +1081,15 @@ public:
FrontFace frontFace() const { return m_frontFace; }
void setFrontFace(FrontFace f) { m_frontFace = f; }
QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
template<typename InputIterator>
void setTargetBlends(InputIterator first, InputIterator last)
{
m_targetBlends.clear();
std::copy(first, last, std::back_inserter(m_targetBlends));
}
const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
bool hasDepthTest() const { return m_depthTest; }
void setDepthTest(bool enable) { m_depthTest = enable; }
@ -1073,8 +1121,19 @@ public:
float lineWidth() const { return m_lineWidth; }
void setLineWidth(float width) { m_lineWidth = width; }
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
template<typename InputIterator>
void setShaderStages(InputIterator first, InputIterator last)
{
m_shaderStages.clear();
std::copy(first, last, std::back_inserter(m_shaderStages));
}
void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed
{
setShaderStages(stages.cbegin(), stages.cend());
}
const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
@ -1093,7 +1152,7 @@ protected:
Topology m_topology = Triangles;
CullMode m_cullMode = None;
FrontFace m_frontFace = CCW;
QVector<TargetBlend> m_targetBlends;
QVarLengthArray<TargetBlend, 8> m_targetBlends;
bool m_depthTest = false;
bool m_depthWrite = false;
CompareOp m_depthOp = Less;
@ -1104,7 +1163,7 @@ protected:
quint32 m_stencilWriteMask = 0xFF;
int m_sampleCount = 1;
float m_lineWidth = 1.0f;
QVector<QRhiShaderStage> m_shaderStages;
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
QRhiVertexInputLayout m_vertexInputLayout;
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;

View File

@ -381,57 +381,6 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
class Q_GUI_EXPORT QRhiShaderResourceBindingPrivate
{
public:
QRhiShaderResourceBindingPrivate()
: ref(1)
{
}
QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other)
: ref(1),
binding(other->binding),
stage(other->stage),
type(other->type),
u(other->u)
{
}
static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; }
static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; }
QAtomicInt ref;
int binding;
QRhiShaderResourceBinding::StageFlags stage;
QRhiShaderResourceBinding::Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
bool hasDynamicOffset;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
struct StorageImageData {
QRhiTexture *tex;
int level;
};
struct StorageBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
StorageImageData simage;
StorageBufferData sbuf;
} u;
};
template<typename T>
struct QRhiBatchedBindings
{
@ -554,28 +503,32 @@ public:
const UsageState &state);
struct Buffer {
QRhiBuffer *buf;
int slot;
BufferAccess access;
BufferStage stage;
UsageState stateAtPassBegin;
};
const QVector<Buffer> *buffers() const { return &m_buffers; }
using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
BufferIterator cendBuffers() const { return m_buffers.cend(); }
struct Texture {
QRhiTexture *tex;
TextureAccess access;
TextureStage stage;
UsageState stateAtPassBegin;
};
const QVector<Texture> *textures() const { return &m_textures; }
using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
TextureIterator cendTextures() const { return m_textures.cend(); }
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
private:
QVector<Buffer> m_buffers;
QVector<Texture> m_textures;
QHash<QRhiBuffer *, Buffer> m_buffers;
QHash<QRhiTexture *, Texture> m_textures;
};
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);

View File

@ -36,7 +36,7 @@
#include "qrhid3d11_p_p.h"
#include "qshader_p.h"
#include "cs_tdr.h"
#include "cs_tdr_p.h"
#include <QWindow>
#include <QOperatingSystemVersion>
#include <qmath.h>
@ -598,7 +598,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
bool hasDynamicOffsetInSrb = false;
bool srbUpdate = false;
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -1746,7 +1746,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
srbD->csUAVs.clear();
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -3082,11 +3082,11 @@ bool QD3D11ShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
boundResourceData.resize(sortedBindings.count());
@ -3939,9 +3939,16 @@ bool QD3D11SwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
currentFrameSlot = 0;

View File

@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
QRhiBatchedBindings<UINT> vsubufoffsets;

View File

@ -39,6 +39,7 @@
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtGui/private/qopenglextensions_p.h>
#include <QtGui/private/qopenglprogrambinarycache_p.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
@ -275,6 +276,8 @@ QT_BEGIN_NAMESPACE
#define GL_POINT_SPRITE 0x8861
#endif
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
/*!
Constructs a new QRhiGles2InitParams.
@ -583,7 +586,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag
int QRhiGles2::ubufAlignment() const
{
return 256;
// No real uniform buffers are used so no need to pretend there is any
// alignment requirement.
return 1;
}
bool QRhiGles2::isYUpInFramebuffer() const
@ -863,7 +868,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
bool hasDynamicOffsetInSrb = false;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
// no BufUniformRead / AccessUniform because no real uniform buffers are used
@ -2181,7 +2186,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
GLbitfield barriers = 0;
QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]);
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
// we only care about after-write, not any other accesses, and
// cannot tell if something was written in a shader several passes
// ago: now the previously written resource may be used with an
@ -2189,17 +2193,16 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
// barrier in theory. Hence setting all barrier bits whenever
// something previously written is used for the first time in a
// subsequent pass.
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access);
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
{
barriers |= GL_ALL_BARRIER_BITS;
}
}
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
for (const QRhiPassResourceTracker::Texture &t : *textures) {
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access);
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
{
@ -2301,7 +2304,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
int texUnit = 0;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -2707,8 +2710,7 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
}
}
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
QShaderDescription *desc, int *glslVersionUsed)
QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
{
const QShader bakedShader = shaderStage.shader();
QVector<int> versionsToTry;
@ -2727,8 +2729,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
QShaderVersion ver(v, QShaderVersion::GlslEs);
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
if (glslVersionUsed)
*glslVersionUsed = v;
if (glslVersion)
*glslVersion = v;
break;
}
}
@ -2757,8 +2759,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
for (int v : versionsToTry) {
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
if (glslVersionUsed)
*glslVersionUsed = v;
if (glslVersion)
*glslVersion = v;
break;
}
}
@ -2766,8 +2768,15 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
if (source.isEmpty()) {
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
<< ") in baked shader" << bakedShader;
return false;
}
return source;
}
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion)
{
const QByteArray source = shaderSource(shaderStage, glslVersion);
if (source.isEmpty())
return false;
GLuint shader;
auto cacheIt = m_shaderCache.constFind(shaderStage);
@ -2804,7 +2813,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
f->glAttachShader(program, shader);
*desc = bakedShader.description();
return true;
}
@ -2859,6 +2867,68 @@ void QRhiGles2::gatherSamplers(GLuint program, const QShaderDescription::InOutVa
}
}
bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper checker;
return checker.get(ctx)->isSupported();
}
static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
{
switch (type) {
case QRhiShaderStage::Vertex:
return QShader::VertexStage;
case QRhiShaderStage::Fragment:
return QShader::FragmentStage;
case QRhiShaderStage::Compute:
return QShader::ComputeStage;
default:
Q_UNREACHABLE();
return QShader::VertexStage;
}
}
QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
GLuint program, QByteArray *cacheKey)
{
QRhiGles2::DiskCacheResult result = QRhiGles2::DiskCacheMiss;
QByteArray diskCacheKey;
if (isProgramBinaryDiskCacheEnabled()) {
QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
for (int i = 0; i < stageCount; ++i) {
const QRhiShaderStage &stage(stages[i]);
const QByteArray source = shaderSource(stage, nullptr);
if (source.isEmpty())
return QRhiGles2::DiskCacheError;
binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(toShaderStage(stage.type()), source));
}
diskCacheKey = binaryProgram.cacheKey();
if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
program, diskCacheKey.constData());
result = QRhiGles2::DiskCacheHit;
}
}
if (cacheKey)
*cacheKey = diskCacheKey;
return result;
}
void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
{
if (isProgramBinaryDiskCacheEnabled()) {
qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
program, cacheKey.constData());
qrhi_programBinaryCache.save(cacheKey, program);
}
}
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
: QRhiBuffer(rhi, type, usage, size)
{
@ -3545,17 +3615,29 @@ bool QGles2GraphicsPipeline::build()
program = rhiD->f->glCreateProgram();
QByteArray diskCacheKey;
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(m_shaderStages.constData(),
m_shaderStages.count(),
program,
&diskCacheKey);
if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
QShaderDescription vsDesc;
QShaderDescription fsDesc;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
if (isVertex) {
if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
vsDesc = shaderStage.shader().description();
} else if (isFragment) {
if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
fsDesc = shaderStage.shader().description();
}
}
@ -3564,9 +3646,12 @@ bool QGles2GraphicsPipeline::build()
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
}
if (!rhiD->linkProgram(program))
if (needsCompile && !rhiD->linkProgram(program))
return false;
if (needsCompile)
rhiD->trySaveToDiskCache(program, diskCacheKey);
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
@ -3627,11 +3712,24 @@ bool QGles2ComputePipeline::build()
program = rhiD->f->glCreateProgram();
QShaderDescription csDesc;
if (!rhiD->compileShader(program, m_shaderStage, &csDesc, nullptr))
QByteArray diskCacheKey;
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(&m_shaderStage, 1, program, &diskCacheKey);
if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
if (!rhiD->linkProgram(program))
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
return false;
csDesc = m_shaderStage.shader().description();
if (needsCompile && !rhiD->linkProgram(program))
return false;
if (needsCompile)
rhiD->trySaveToDiskCache(program, diskCacheKey);
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
@ -3705,6 +3803,13 @@ bool QGles2SwapChain::buildOrResize()
m_currentPixelSize = surfacePixelSize();
pixelSize = m_currentPixelSize;
if (m_depthStencil && m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)
&& m_depthStencil->pixelSize() != pixelSize)
{
m_depthStencil->setPixelSize(pixelSize);
m_depthStencil->build();
}
rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
rt.d.pixelSize = pixelSize;
rt.d.dpr = float(m_window->devicePixelRatio());

View File

@ -692,13 +692,23 @@ public:
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
int effectiveSampleCount(int sampleCount) const;
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
QShaderDescription *desc, int *glslVersionUsed);
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program);
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst);
bool isProgramBinaryDiskCacheEnabled() const;
enum DiskCacheResult {
DiskCacheHit,
DiskCacheMiss,
DiskCacheError
};
DiskCacheResult tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
GLuint program, QByteArray *cacheKey);
void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
QOpenGLContext *ctx = nullptr;
bool importedContext = false;

View File

@ -656,7 +656,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
} res[KNOWN_STAGES];
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
@ -875,7 +875,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
// do buffer writes, figure out if we need to rebind, and mark as in-use
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -1036,44 +1036,11 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
}
}
QSize safeOutputSize(QRhiMetal *rhiD, QMetalCommandBuffer *cbD)
{
QSize size = cbD->currentTarget->pixelSize();
// So now we have the issue that the texture (drawable) size may have
// changed again since swapchain buildOrResize() was called. This can
// happen for example when interactively resizing the window a lot in one
// go, and command buffer building happens on a dedicated thread (f.ex.
// using the threaded render loop of Qt Quick).
//
// This is only an issue when running in debug mode with XCode because Metal
// validation will fail when setting viewport or scissor with the real size
// being smaller than what we think it is. So query the drawable size right
// here, in debug mode at least.
//
// In addition, we have to take the smaller of the two widths and heights
// to be safe, apparently. In some cases validation seems to think that the
// "render pass width" (or height) is the old(?) value.
#ifdef QT_DEBUG
if (cbD->currentTarget->resourceType() == QRhiResource::RenderTarget) {
Q_ASSERT(rhiD->currentSwapChain);
const QSize otherSize = rhiD->currentSwapChain->surfacePixelSize();
size.setWidth(qMin(size.width(), otherSize.width()));
size.setHeight(qMin(size.height(), otherSize.height()));
}
#else
Q_UNUSED(rhiD);
#endif
return size;
}
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
{
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
const QSize outputSize = safeOutputSize(this, cbD);
const QSize outputSize = cbD->currentTarget->pixelSize();
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
float x, y, w, h;
@ -1105,7 +1072,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
const QSize outputSize = safeOutputSize(this, cbD);
const QSize outputSize = cbD->currentTarget->pixelSize();
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
int x, y, w, h;
@ -2801,21 +2768,21 @@ bool QMetalShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
if (!sortedBindings.isEmpty())
maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding;
maxBinding = sortedBindings.last().data()->binding;
else
maxBinding = -1;
boundResourceData.resize(sortedBindings.count());
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -3529,20 +3496,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
QSize QMetalSwapChain::surfacePixelSize()
{
// may be called before build, must not access other than m_*
NSView *v = (NSView *) m_window->winId();
if (v) {
CAMetalLayer *layer = (CAMetalLayer *) [v layer];
if (layer) {
CGSize size = layer.bounds.size;
size.width *= layer.contentsScale;
size.height *= layer.contentsScale;
layer.drawableSize = size;
return QSize(int(size.width), int(size.height));
}
}
return QSize();
Q_ASSERT(m_window);
return m_window->size() * m_window->devicePixelRatio();
}
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
@ -3593,8 +3548,9 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
NSView *v = (NSView *) window->winId();
d->layer = (CAMetalLayer *) [v layer];
NSView *view = reinterpret_cast<NSView *>(window->winId());
Q_ASSERT(view);
d->layer = static_cast<CAMetalLayer *>(view.layer);
Q_ASSERT(d->layer);
chooseFormats();
@ -3623,7 +3579,15 @@ bool QMetalSwapChain::buildOrResize()
d->layer.opaque = YES;
}
m_currentPixelSize = surfacePixelSize();
// Now set the layer's drawableSize which will stay set to the same value
// until the next buildOrResize(), thus ensuring atomicity with regards to
// the drawable size in frames.
CGSize layerSize = d->layer.bounds.size;
layerSize.width *= d->layer.contentsScale;
layerSize.height *= d->layer.contentsScale;
d->layer.drawableSize = layerSize;
m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize();
pixelSize = m_currentPixelSize;
[d->layer setDevice: rhiD->d->dev];
@ -3644,9 +3608,16 @@ bool QMetalSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
rtWrapper.d->pixelSize = pixelSize;

View File

@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;

View File

@ -2313,7 +2313,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
VkWriteDescriptorSet writeInfo;
@ -3556,12 +3556,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
if (tracker.isEmpty())
return;
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf);
VkAccessFlags access = toVkAccess(b.access);
VkPipelineStageFlags stage = toVkPipelineStage(b.stage);
QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin);
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
VkAccessFlags access = toVkAccess(it->access);
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin);
if (!s.stage)
continue;
if (s.access == access && s.stage == stage) {
@ -3575,7 +3574,7 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufMemBarrier.srcAccessMask = s.access;
bufMemBarrier.dstAccessMask = access;
bufMemBarrier.buffer = bufD->buffers[b.slot];
bufMemBarrier.buffer = bufD->buffers[it->slot];
bufMemBarrier.size = VK_WHOLE_SIZE;
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
0, nullptr,
@ -3583,13 +3582,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
0, nullptr);
}
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
for (const QRhiPassResourceTracker::Texture &t : *textures) {
QVkTexture *texD = QRHI_RES(QVkTexture, t.tex);
VkImageLayout layout = toVkLayout(t.access);
VkAccessFlags access = toVkAccess(t.access);
VkPipelineStageFlags stage = toVkPipelineStage(t.stage);
QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin);
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
VkImageLayout layout = toVkLayout(it->access);
VkAccessFlags access = toVkAccess(it->access);
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin);
if (s.access == access && s.stage == stage && s.layout == layout) {
if (!accessIsWrite(access))
continue;
@ -3870,7 +3868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
bool hasDynamicOffsetInSrb = false;
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
@ -3889,7 +3887,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// Do host writes and mark referenced shader resources as in-use.
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
switch (b->type) {
@ -4022,7 +4020,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// and neither srb nor dynamicOffsets has any such ordering
// requirement.
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
uint32_t offset = 0;
for (int i = 0; i < dynamicOffsetCount; ++i) {
@ -4750,7 +4748,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic
dst->compareOp = toVkCompareOp(src.compareOp);
}
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b)
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
{
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@ -5697,16 +5695,17 @@ bool QVkShaderResourceBindings::build()
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
descSets[i] = VK_NULL_HANDLE;
sortedBindings = m_bindings;
sortedBindings.clear();
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
return a.data()->binding < b.data()->binding;
});
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
const QRhiShaderResourceBinding::Data *b = binding.data();
VkDescriptorSetLayoutBinding vkbinding;
memset(&vkbinding, 0, sizeof(vkbinding));
vkbinding.binding = uint32_t(b->binding);
@ -6315,9 +6314,16 @@ bool QVkSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
m_depthStencil->setPixelSize(pixelSize);
if (!m_depthStencil->build())
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
pixelSize.width(), pixelSize.height());
} else {
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
pixelSize.width(), pixelSize.height());
}
}
if (!m_renderPassDesc)

View File

@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int poolIndex = -1;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
friend class QRhiVulkan;
};

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -2096,10 +2096,11 @@ uint qHash(const QFont &font, uint seed) noexcept
*/
bool QFont::fromString(const QString &descrip)
{
const auto l = descrip.splitRef(QLatin1Char(','));
int count = l.count();
if (!count || (count > 2 && count < 9) || count > 11) {
const QStringRef sr = QStringRef(&descrip).trimmed();
const auto l = sr.split(QLatin1Char(','));
const int count = l.count();
if (!count || (count > 2 && count < 9) || count > 11 ||
l.first().isEmpty()) {
qWarning("QFont::fromString: Invalid description '%s'",
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
return false;

View File

@ -467,6 +467,14 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
if (fallbackList.isEmpty())
return fallbackList;
// .Apple Symbols Fallback will be at the beginning of the list and we will
// detect that this has glyphs for Arabic and other writing systems.
// Since it is a symbol font, it should be the last resort, so that
// the proper fonts for these writing systems are preferred.
int symbolIndex = fallbackList.indexOf(QLatin1String(".Apple Symbols Fallback"));
if (symbolIndex >= 0)
fallbackList.move(symbolIndex, fallbackList.size() - 1);
#if defined(Q_OS_MACOS)
// Since we are only returning a list of default fonts for the current language, we do not
// cover all Unicode completely. This was especially an issue for some of the common script
@ -481,6 +489,15 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
fallbackList.append(QStringLiteral("Apple Symbols"));
#endif
// Since iOS 13, the cascade list may contain meta-fonts which have not been
// populated to the database, such as ".AppleJapaneseFont". It is important that we
// include this in the fallback list, in order to get fallback support for all
// languages
for (const QString &fallback : fallbackList) {
if (!QPlatformFontDatabase::isFamilyPopulated(fallback))
const_cast<QCoreTextFontDatabase *>(this)->populateFamily(fallback);
}
extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &);
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);

View File

@ -465,7 +465,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
return QStringList(QLatin1String("android"));
}
return QStringList(QLatin1String("fusion"));
case DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::AndroidLayout);
case MouseDoubleClickDistance:
{
int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
@ -489,8 +490,6 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
Q_FALLTHROUGH();
}
case DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::AndroidLayout);
default:
return QPlatformTheme::themeHint(hint);
}

View File

@ -881,7 +881,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
return;
}
int serial = serialNumber.load();
int serial = serialNumber.loadRelaxed();
if (!threadData->canWait || (serial != lastSerial)) {
lastSerial = serial;
QCoreApplication::sendPostedEvents();

View File

@ -43,9 +43,7 @@
- (void)initDrawing
{
self.wantsLayer = [self layerExplicitlyRequested]
|| [self shouldUseMetalLayer]
|| [self layerEnabledByMacOS];
[self updateLayerBacking];
// Enable high-DPI OpenGL for retina displays. Enabling has the side
// effect that Cocoa will start calling glViewport(0, 0, width, height),
@ -71,22 +69,13 @@
return YES;
}
- (void)drawRect:(NSRect)dirtyRect
// ----------------------- Layer setup -----------------------
- (void)updateLayerBacking
{
Q_UNUSED(dirtyRect);
if (!m_platformWindow)
return;
QRegion exposedRegion;
const NSRect *dirtyRects;
NSInteger numDirtyRects;
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
for (int i = 0; i < numDirtyRects; ++i)
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
m_platformWindow->handleExposeEvent(exposedRegion);
self.wantsLayer = [self layerEnabledByMacOS]
|| [self layerExplicitlyRequested]
|| [self shouldUseMetalLayer];
}
- (BOOL)layerEnabledByMacOS
@ -123,40 +112,81 @@
return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
}
/*
This method is called by AppKit when layer-backing is requested by
setting wantsLayer too YES (via -[NSView _updateLayerBackedness]),
or in cases where AppKit itself decides that a view should be
layer-backed.
Note however that some code paths in AppKit will not go via this
method for creating the backing layer, and will instead create the
layer manually, and just call setLayer. An example of this is when
an NSOpenGLContext is attached to a view, in which case AppKit will
create a new layer in NSOpenGLContextSetLayerOnViewIfNecessary.
For this reason we leave the implementation of this override as
minimal as possible, only focusing on creating the appropriate
layer type, and then leave it up to setLayer to do the work of
making sure the layer is set up correctly.
*/
- (CALayer *)makeBackingLayer
{
if ([self shouldUseMetalLayer]) {
// Check if Metal is supported. If it isn't then it's most likely
// too late at this point and the QWindow will be non-functional,
// but we can at least print a warning.
if (![MTLCreateSystemDefaultDevice() autorelease]) {
qWarning() << "QWindow initialization error: Metal is not supported";
return [super makeBackingLayer];
if ([MTLCreateSystemDefaultDevice() autorelease]) {
return [CAMetalLayer layer];
} else {
qCWarning(lcQpaDrawing) << "Failed to create QWindow::MetalSurface."
<< "Metal is not supported by any of the GPUs in this system.";
}
CAMetalLayer *layer = [CAMetalLayer layer];
// Set the contentsScale for the layer. This is normally done in
// viewDidChangeBackingProperties, however on startup that function
// is called before the layer is created here. The layer's drawableSize
// is updated from layoutSublayersOfLayer as usual.
layer.contentsScale = self.window.backingScaleFactor;
return layer;
}
return [super makeBackingLayer];
}
/*
This method is called by AppKit whenever the view is asked to change
its layer, which can happen both as a result of enabling layer-backing,
or when a layer is set explicitly. The latter can happen both when a
view is layer-hosting, or when AppKit internals are switching out the
layer-backed view, as described above for makeBackingLayer.
*/
- (void)setLayer:(CALayer *)layer
{
qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
qCDebug(lcQpaDrawing) << "Making" << self
<< (self.wantsLayer ? "layer-backed" : "layer-hosted")
<< "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
if (layer.delegate && layer.delegate != self) {
qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate
<< "This delegate is responsible for all view updates for" << self;
} else {
layer.delegate = self;
}
[super setLayer:layer];
layer.delegate = self;
// When adding a view to a view hierarchy the backing properties will change
// which results in updating the contents scale, but in case of switching the
// layer on a view that's already in a view hierarchy we need to manually ensure
// the scale is up to date.
if (self.superview)
[self updateLayerContentsScale];
if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
// If the view claims to be opaque we expect it to fill the entire
// layer with content, in which case we want to detect any areas
// where it doesn't.
layer.backgroundColor = NSColor.magentaColor.CGColor;
}
}
// ----------------------- Layer updates -----------------------
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
{
// We need to set this explicitly since the super implementation
@ -164,17 +194,95 @@
return NSViewLayerContentsRedrawDuringViewResize;
}
#if 0 // Disabled until we enable lazy backingstore resizing
- (NSViewLayerContentsPlacement)layerContentsPlacement
{
// Always place the layer at top left without any automatic scaling,
// so that we can re-use larger layers when resizing a window down.
// Always place the layer at top left without any automatic scaling.
// This will highlight situations where we're missing content for the
// layer by not responding to the displayLayer: request synchronously.
// It also allows us to re-use larger layers when resizing a window down.
return NSViewLayerContentsPlacementTopLeft;
}
#endif
- (void)viewDidChangeBackingProperties
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
if (self.layer)
[self updateLayerContentsScale];
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
// For now we trigger an expose, and let QCocoaBackingStore deal with
// buffer invalidation internally.
[self setNeedsDisplay:YES];
}
- (void)updateLayerContentsScale
{
// We expect clients to fill the layer with retina aware content,
// based on the devicePixelRatio of the QWindow, so we set the
// layer's content scale to match that. By going via devicePixelRatio
// instead of applying the NSWindow's backingScaleFactor, we also take
// into account OpenGL views with wantsBestResolutionOpenGLSurface set
// to NO. In this case the window will have a backingScaleFactor of 2,
// but the QWindow will have a devicePixelRatio of 1.
auto devicePixelRatio = m_platformWindow->devicePixelRatio();
qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio;
self.layer.contentsScale = devicePixelRatio;
}
/*
This method is called by AppKit to determine whether it should update
the contentScale of the layer to match the window backing scale.
We always return NO since we're updating the contents scale manually.
*/
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
{
Q_UNUSED(layer); Q_UNUSED(scale); Q_UNUSED(window);
return NO;
}
// ----------------------- Draw callbacks -----------------------
/*
This method is called by AppKit for the non-layer case, where we are
drawing into the NSWindow's surface.
*/
- (void)drawRect:(NSRect)dirtyBoundingRect
{
Q_ASSERT_X(!self.layer, "QNSView",
"The drawRect code path should not be hit when we are layer backed");
if (!m_platformWindow)
return;
QRegion exposedRegion;
const NSRect *dirtyRects;
NSInteger numDirtyRects;
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
for (int i = 0; i < numDirtyRects; ++i)
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
if (exposedRegion.isEmpty())
exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect();
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
m_platformWindow->handleExposeEvent(exposedRegion);
}
/*
This method is called by AppKit when we are layer-backed, where
we are drawing into the layer.
*/
- (void)displayLayer:(CALayer *)layer
{
Q_ASSERT_X(self.layer && layer == self.layer, "QNSView",
"The displayLayer code path should only be hit for our own layer");
if (!m_platformWindow)
return;
if (!NSThread.isMainThread) {
// Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
// which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
@ -184,29 +292,8 @@
return;
}
Q_ASSERT(layer == self.layer);
if (!m_platformWindow)
return;
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
// FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
}
- (void)viewDidChangeBackingProperties
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
if (self.layer)
self.layer.contentsScale = self.window.backingScaleFactor;
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
// For now we trigger an expose, and let QCocoaBackingStore deal with
// buffer invalidation internally.
[self setNeedsDisplay:YES];
}
@end

View File

@ -891,13 +891,6 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
result.profile = QSurfaceFormat::CoreProfile;
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
result.profile = QSurfaceFormat::CompatibilityProfile;
if (result.version < 0x0400)
return result;
// v4.0 onwards
value = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
if (value == LOSE_CONTEXT_ON_RESET_ARB)
result.options |= QSurfaceFormat::ResetNotification;
return result;
}
@ -975,6 +968,7 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
*/
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
#define ROBUSTNESS_EXTENSION "GL_ARB_robustness"
QOpenGLStaticContext::QOpenGLStaticContext() :
vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
@ -995,9 +989,31 @@ QOpenGLStaticContext::QOpenGLStaticContext() :
wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
{
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
extensions |= SampleBuffers;
if (defaultFormat.version < 0x0300) {
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
extensions |= SampleBuffers;
if (extensionNames.startsWith(ROBUSTNESS_EXTENSION " ")
|| extensionNames.indexOf(" " ROBUSTNESS_EXTENSION " ") != -1)
extensions |= Robustness;
} else {
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
if (glGetStringi) {
GLint n = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (GLint i = 0; i < n; ++i) {
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
if (p) {
if (!strcmp(p, SAMPLE_BUFFER_EXTENSION))
extensions |= SampleBuffers;
else if (!strcmp(p, ROBUSTNESS_EXTENSION))
extensions |= Robustness;
}
}
}
}
}
QByteArray QOpenGLStaticContext::getGlString(unsigned int which)
@ -1236,27 +1252,11 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
bool hasRobustness = false;
if (m_obtainedFormat.majorVersion() < 3) {
const char *exts = reinterpret_cast<const char *>(QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS));
hasRobustness = exts && strstr(exts, "GL_ARB_robustness");
} else {
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
if (glGetStringi) {
GLint n = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (GLint i = 0; i < n; ++i) {
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
if (p && !strcmp(p, "GL_ARB_robustness")) {
hasRobustness = true;
break;
}
}
}
}
if (hasRobustness) {
if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) {
GLint value = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
if (value == LOSE_CONTEXT_ON_RESET_ARB)
m_obtainedFormat.setOption(QSurfaceFormat::ResetNotification);
m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
}

View File

@ -142,7 +142,8 @@ public:
enum Extensions
{
SampleBuffers = 0x1,
sRGBCapableFramebuffer = 0x2
sRGBCapableFramebuffer = 0x2,
Robustness = 0x4,
};
typedef bool

View File

@ -2697,10 +2697,16 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
return true;
}
if (localPos.y() < 0) {
const int topResizeBarPos = -frameMargins().top();
if (localPos.y() >= topResizeBarPos)
// We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar,
// otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262).
// However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct
// sizing frame height in all Windows versions/scales. This empirical constant seems to work, though.
const int sizingHeight = 9;
const int topResizeBarPos = sizingHeight - frameMargins().top();
if (localPos.y() < topResizeBarPos) {
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
return true;
return true;
}
}
}
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {

View File

@ -79,7 +79,7 @@ QSqlDatabase db = QSqlDatabase::addDatabase("MYDRIVER");
//! [3]
...
db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
if (db.open()) {
// success!
}

View File

@ -2805,8 +2805,11 @@ template <> Q_TESTLIB_EXPORT char *QTest::toString<char>(const char &t)
*/
char *QTest::toString(const char *str)
{
if (!str)
return nullptr;
if (!str) {
char *msg = new char[1];
*msg = '\0';
return msg;
}
char *msg = new char[strlen(str) + 1];
return qstrcpy(msg, str);
}

View File

@ -55,10 +55,14 @@
#if QT_CONFIG(lineedit)
#include "qlineedit.h"
#endif
#include <qpointer.h>
#include "qpainter.h"
#include "qwindow.h"
#include "qpushbutton.h"
#include "qset.h"
#if QT_CONFIG(shortcut)
# include "qshortcut.h"
#endif
#include "qstyle.h"
#include "qvarlengtharray.h"
#if defined(Q_OS_MACX)
@ -232,31 +236,24 @@ void QWizardField::findProperty(const QWizardDefaultProperty *properties, int pr
class QWizardLayoutInfo
{
public:
inline QWizardLayoutInfo()
: topLevelMarginLeft(-1), topLevelMarginRight(-1), topLevelMarginTop(-1),
topLevelMarginBottom(-1), childMarginLeft(-1), childMarginRight(-1),
childMarginTop(-1), childMarginBottom(-1), hspacing(-1), vspacing(-1),
wizStyle(QWizard::ClassicStyle), header(false), watermark(false), title(false),
subTitle(false), extension(false), sideWidget(false) {}
int topLevelMarginLeft;
int topLevelMarginRight;
int topLevelMarginTop;
int topLevelMarginBottom;
int childMarginLeft;
int childMarginRight;
int childMarginTop;
int childMarginBottom;
int hspacing;
int vspacing;
int buttonSpacing;
QWizard::WizardStyle wizStyle;
bool header;
bool watermark;
bool title;
bool subTitle;
bool extension;
bool sideWidget;
int topLevelMarginLeft = -1;
int topLevelMarginRight = -1;
int topLevelMarginTop = -1;
int topLevelMarginBottom = -1;
int childMarginLeft = -1;
int childMarginRight = -1;
int childMarginTop = -1;
int childMarginBottom = -1;
int hspacing = -1;
int vspacing = -1;
int buttonSpacing = -1;
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
bool header = false;
bool watermark = false;
bool title = false;
bool subTitle = false;
bool extension = false;
bool sideWidget = false;
bool operator==(const QWizardLayoutInfo &other);
inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
@ -486,21 +483,18 @@ class QWizardPagePrivate : public QWidgetPrivate
public:
enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
inline QWizardPagePrivate()
: wizard(0), completeState(Tri_Unknown), explicitlyFinal(false), commit(false) {}
bool cachedIsComplete() const;
void _q_maybeEmitCompleteChanged();
void _q_updateCachedCompleteState();
QWizard *wizard;
QWizard *wizard = nullptr;
QString title;
QString subTitle;
QPixmap pixmaps[QWizard::NPixmaps];
QVector<QWizardField> pendingFields;
mutable TriState completeState;
bool explicitlyFinal;
bool commit;
mutable TriState completeState = Tri_Unknown;
bool explicitlyFinal = false;
bool commit = false;
bool initialized = false;
QMap<int, QString> buttonCustomTexts;
};
@ -556,42 +550,6 @@ public:
Forward
};
inline QWizardPrivate()
: start(-1)
, startSetByUser(false)
, current(-1)
, canContinue(false)
, canFinish(false)
, disableUpdatesCount(0)
, wizStyle(QWizard::ClassicStyle)
, opts(0)
, buttonsHaveCustomLayout(false)
, titleFmt(Qt::AutoText)
, subTitleFmt(Qt::AutoText)
, placeholderWidget1(0)
, placeholderWidget2(0)
, headerWidget(0)
, watermarkLabel(0)
, sideWidget(0)
, pageFrame(0)
, titleLabel(0)
, subTitleLabel(0)
, bottomRuler(0)
#if QT_CONFIG(style_windowsvista)
, vistaHelper(0)
, vistaInitPending(true)
, vistaState(QVistaHelper::Dirty)
, vistaStateChanged(false)
, inHandleAeroStyleChange(false)
#endif
, minimumWidth(0)
, minimumHeight(0)
, maximumWidth(QWIDGETSIZE_MAX)
, maximumHeight(QWIDGETSIZE_MAX)
{
std::fill(btns, btns + QWizard::NButtons, static_cast<QAbstractButton *>(0));
}
void init();
void reset();
void cleanupPagesNotInHistory();
@ -631,21 +589,21 @@ public:
QMap<QString, int> fieldIndexMap;
QVector<QWizardDefaultProperty> defaultPropertyTable;
QList<int> history;
int start;
bool startSetByUser;
int current;
bool canContinue;
bool canFinish;
int start = -1;
bool startSetByUser = false;
int current = -1;
bool canContinue = false;
bool canFinish = false;
QWizardLayoutInfo layoutInfo;
int disableUpdatesCount;
int disableUpdatesCount = 0;
QWizard::WizardStyle wizStyle;
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
QWizard::WizardOptions opts;
QMap<int, QString> buttonCustomTexts;
bool buttonsHaveCustomLayout;
bool buttonsHaveCustomLayout = false;
QList<QWizard::WizardButton> buttonsCustomLayout;
Qt::TextFormat titleFmt;
Qt::TextFormat subTitleFmt;
Qt::TextFormat titleFmt = Qt::AutoText;
Qt::TextFormat subTitleFmt = Qt::AutoText;
mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
union {
@ -660,32 +618,35 @@ public:
} btn;
mutable QAbstractButton *btns[QWizard::NButtons];
};
QWizardAntiFlickerWidget *antiFlickerWidget;
QWidget *placeholderWidget1;
QWidget *placeholderWidget2;
QWizardHeader *headerWidget;
QWatermarkLabel *watermarkLabel;
QWidget *sideWidget;
QFrame *pageFrame;
QLabel *titleLabel;
QLabel *subTitleLabel;
QWizardRuler *bottomRuler;
QWizardAntiFlickerWidget *antiFlickerWidget = nullptr;
QWidget *placeholderWidget1 = nullptr;
QWidget *placeholderWidget2 = nullptr;
QWizardHeader *headerWidget = nullptr;
QWatermarkLabel *watermarkLabel = nullptr;
QWidget *sideWidget = nullptr;
QFrame *pageFrame = nullptr;
QLabel *titleLabel = nullptr;
QLabel *subTitleLabel = nullptr;
QWizardRuler *bottomRuler = nullptr;
QVBoxLayout *pageVBoxLayout;
QHBoxLayout *buttonLayout;
QGridLayout *mainLayout;
QVBoxLayout *pageVBoxLayout = nullptr;
QHBoxLayout *buttonLayout = nullptr;
QGridLayout *mainLayout = nullptr;
#if QT_CONFIG(style_windowsvista)
QVistaHelper *vistaHelper;
bool vistaInitPending;
QVistaHelper::VistaState vistaState;
bool vistaStateChanged;
bool inHandleAeroStyleChange;
QVistaHelper *vistaHelper = nullptr;
# if QT_CONFIG(shortcut)
QPointer<QShortcut> vistaNextShortcut;
# endif
bool vistaInitPending = true;
QVistaHelper::VistaState vistaState = QVistaHelper::Dirty;
bool vistaStateChanged = false;
bool inHandleAeroStyleChange = false;
#endif
int minimumWidth;
int minimumHeight;
int maximumWidth;
int maximumHeight;
int minimumWidth = 0;
int minimumHeight = 0;
int maximumWidth = QWIDGETSIZE_MAX;
int maximumHeight = QWIDGETSIZE_MAX;
};
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
@ -720,6 +681,8 @@ void QWizardPrivate::init()
{
Q_Q(QWizard);
std::fill(btns, btns + QWizard::NButtons, nullptr);
antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
if (wizStyle == QWizard::MacStyle) {
@ -1461,10 +1424,17 @@ void QWizardPrivate::updateButtonTexts()
// Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
// even in RTL mode, so do the same, even if it might be counter-intuitive.
// The shortcut for 'back' is set in class QVistaBackButton.
#if QT_CONFIG(shortcut)
if (btns[QWizard::NextButton] && isVistaThemeEnabled())
btns[QWizard::NextButton]->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Right));
#endif
#if QT_CONFIG(shortcut) && QT_CONFIG(style_windowsvista)
if (btns[QWizard::NextButton] && isVistaThemeEnabled()) {
if (vistaNextShortcut.isNull()) {
vistaNextShortcut =
new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right),
btns[QWizard::NextButton], SLOT(animateClick()));
}
} else {
delete vistaNextShortcut;
}
#endif // shortcut && style_windowsvista
}
void QWizardPrivate::updateButtonLayout()

View File

@ -6204,7 +6204,7 @@ void QWidget::setFocusProxy(QWidget * w)
if (changingAppFocusWidget) {
QWidget *newDeepestFocusProxy = d_func()->deepestFocusProxy();
QApplicationPrivate::focus_widget = newDeepestFocusProxy ? newDeepestFocusProxy : this;
QApplicationPrivate::setFocusWidget(newDeepestFocusProxy ? newDeepestFocusProxy : this, Qt::NoFocusReason);
}
}

View File

@ -5967,6 +5967,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
case SP_ArrowLeft:
icon = QIcon::fromTheme(QLatin1String("go-previous"));
break;
case SP_DialogNoButton:
case SP_DialogCancelButton:
icon = QIcon::fromTheme(QLatin1String("dialog-cancel"),
QIcon::fromTheme(QLatin1String("process-stop")));

View File

@ -44,6 +44,9 @@ private slots:
void fuzzyCompare();
void rawNaN_data();
void rawNaN();
#if QT_CONFIG(signaling_nan)
void distinctNaN();
#endif
void generalNaN_data();
void generalNaN();
void infinity();
@ -139,6 +142,9 @@ void tst_QNumeric::rawNaN_data()
QTest::addColumn<double>("nan");
QTest::newRow("quiet") << qQNaN();
#if QT_CONFIG(signaling_nan)
QTest::newRow("signaling") << qSNaN();
#endif
}
void tst_QNumeric::rawNaN()
@ -147,6 +153,15 @@ void tst_QNumeric::rawNaN()
checkNaN(nan);
}
#if QT_CONFIG(signaling_nan)
void tst_QNumeric::distinctNaN()
{
const double qnan = qQNaN();
const double snan = qSNaN();
QVERIFY(memcmp(&qnan, &snan, sizeof(double)) != 0);
}
#endif
void tst_QNumeric::generalNaN_data()
{
QTest::addColumn<int>("most");

View File

@ -320,7 +320,7 @@ void tst_QRandomGenerator::generate32_data()
QTest::newRow("fixed") << (RandomValue32 & RandomDataMask);
QTest::newRow("global") << 0U;
#ifdef QT_BUILD_INTERNAL
if (qt_has_hwrng())
if (qHasHwrng())
QTest::newRow("hwrng") << uint(UseSystemRNG);
QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG);
# ifdef HAVE_FALLBACK_ENGINE
@ -755,7 +755,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data()
auto newRow = [&](quint32 max) {
#ifdef QT_BUILD_INTERNAL
if (qt_has_hwrng())
if (qHasHwrng())
QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max;
QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max;
# ifdef HAVE_FALLBACK_ENGINE
@ -868,7 +868,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data()
auto newRow = [&](double min, double sup) {
#ifdef QT_BUILD_INTERNAL
if (qt_has_hwrng())
if (qHasHwrng())
QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup;
QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup;
# ifdef HAVE_FALLBACK_ENGINE

View File

@ -1413,10 +1413,12 @@ void tst_QCborValue::toCbor_data()
// The rest of these tests are conversions whose decoding does not yield
// back the same QCborValue.
#if QT_CONFIG(signaling_nan)
// Signalling NaN get normalized to quiet ones
QTest::newRow("Double:snan") << QCborValue(qSNaN()) << raw("\xfb\x7f\xf8\0""\0\0\0\0\0") << QCborValue::EncodingOptions();
QTest::newRow("Float:snan") << QCborValue(qSNaN()) << raw("\xfa\x7f\xc0\0\0") << QCborValue::EncodingOptions(QCborValue::UseFloat);
QTest::newRow("Float16:snan") << QCborValue(qSNaN()) << raw("\xf9\x7e\0") << QCborValue::EncodingOptions(QCborValue::UseFloat16);
#endif
// Floating point written as integers are read back as integers
QTest::newRow("UseInteger:0") << QCborValue(0.) << raw("\x00") << QCborValue::EncodingOptions(QCborValue::UseIntegers);

View File

@ -3468,6 +3468,9 @@ void tst_QDateTime::timeZones() const
void tst_QDateTime::systemTimeZoneChange() const
{
#ifdef Q_OS_WINRT
QSKIP("UWP applications cannot change the system`s time zone (sandboxing)");
#endif
// Set the timezone to Brisbane time
TimeZoneRollback useZone(QByteArray("AEST-10:00"));
@ -3485,9 +3488,6 @@ void tst_QDateTime::systemTimeZoneChange() const
useZone.reset(QByteArray("IST-05:30"));
QCOMPARE(localDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime));
#ifdef Q_OS_WINRT
QEXPECT_FAIL("", "WinRT gets this wrong, QTBUG-71185", Continue);
#endif
QVERIFY(localMsecs != localDate.toMSecsSinceEpoch());
QCOMPARE(utcDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC));
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);

View File

@ -1,2 +0,0 @@
[insert_remove_loop]
msvc-2019

View File

@ -0,0 +1,6 @@
[basic]
winrt
[resize]
winrt
[painter]
winrt

View File

@ -4,5 +4,3 @@ TARGET = tst_qopenglwindow
QT += core-private gui-private testlib
SOURCES += tst_qopenglwindow.cpp
win32:CONFIG+=insignificant_test # QTBUG-46452, QTBUG-49630

View File

@ -88,7 +88,9 @@ private slots:
void testToFillPolygons();
#if QT_CONFIG(signaling_nan)
void testNaNandInfinites();
#endif
void closing();
@ -1228,6 +1230,7 @@ void tst_QPainterPath::testToFillPolygons()
QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
}
#if QT_CONFIG(signaling_nan)
void tst_QPainterPath::testNaNandInfinites()
{
QPainterPath path1;
@ -1271,6 +1274,7 @@ void tst_QPainterPath::testNaNandInfinites()
path1.lineTo(QPointF(1, 1));
QVERIFY(path1 != path2);
}
#endif // signaling_nan
void tst_QPainterPath::connectPathDuplicatePoint()
{

View File

@ -66,6 +66,8 @@ private slots:
void defaultFamily();
void toAndFromString();
void fromStringWithoutStyleName();
void fromDegenerateString_data();
void fromDegenerateString();
void sharing();
void familyNameWithCommaQuote_data();
@ -604,6 +606,25 @@ void tst_QFont::fromStringWithoutStyleName()
QCOMPARE(font2.toString(), str);
}
void tst_QFont::fromDegenerateString_data()
{
QTest::addColumn<QString>("string");
QTest::newRow("empty") << QString();
QTest::newRow("justAComma") << ",";
QTest::newRow("commasAndSpaces") << " , , ";
QTest::newRow("spaces") << " ";
QTest::newRow("spacesTabsAndNewlines") << " \t \n";
}
void tst_QFont::fromDegenerateString()
{
QFETCH(QString, string);
QFont f;
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Invalid description.*"));
QCOMPARE(f.fromString(string), false);
QCOMPARE(f, QFont());
}
void tst_QFont::sharing()
{

View File

@ -2712,13 +2712,8 @@ void tst_QWizard::taskQTBUG_46894_nextButtonShortcut()
wizard.show();
QVERIFY(QTest::qWaitForWindowExposed(&wizard));
if (wizard.button(QWizard::NextButton)->text() == "&Next") {
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
QKeySequence(Qt::ALT | Qt::Key_Right));
} else {
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
}
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
}
}

View File

@ -379,7 +379,7 @@ void TiledPixmapPainter::paintEvent(QPaintEvent *event)
// large pixmap: 2 x 2 tiles
// 2x pixmap : 4 x 4 tiles
//
// On a 2x display the 2x pimxap tiles
// On a 2x display the 2x pixmap tiles
// will be drawn in high resolution.
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X);
yoff += tiles * pixmapEdge + 10;

View File

@ -298,7 +298,7 @@ void Window::init()
m_sc = m_r->newSwapChain();
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
releasePool << m_ds;
@ -376,16 +376,12 @@ void Window::releaseResources()
void Window::resizeSwapChain()
{
const QSize outputSize = m_sc->surfacePixelSize();
m_ds->setPixelSize(outputSize);
m_ds->build(); // == m_ds->release(); m_ds->build();
m_hasSwapChain = m_sc->buildOrResize();
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
m_elapsedMs = 0;
m_elapsedCount = 0;
const QSize outputSize = m_sc->currentPixelSize();
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);

View File

@ -200,12 +200,10 @@ void Window::customInit()
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
});
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
for (int i = 0; i < ATTCOUNT; ++i) {
QRhiGraphicsPipeline::TargetBlend blend;
blends.append(blend);
}
d.triPs->setTargetBlends(blends);
QRhiGraphicsPipeline::TargetBlend blends[ATTCOUNT]; // defaults to blending == false
d.triPs->setTargetBlends(blends, blends + ATTCOUNT);
inputLayout.setBindings({
{ 5 * sizeof(float) }
});

View File

@ -240,7 +240,7 @@ void Window::customInit()
#else
d.msaaTriPs->setSampleCount(1);
#endif
d.msaaTriPs->setShaderStages(d.triPs->shaderStages());
d.msaaTriPs->setShaderStages(d.triPs->cbeginShaderStages(), d.triPs->cendShaderStages());
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);

View File

@ -400,7 +400,7 @@ void Window::init()
{
m_sc = r.r->newSwapChain();
m_ds = r.r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(),
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
m_releasePool << m_ds;
@ -427,13 +427,9 @@ void Window::releaseResources()
void Window::resizeSwapChain()
{
const QSize outputSize = m_sc->surfacePixelSize();
m_ds->setPixelSize(outputSize);
m_ds->build();
m_hasSwapChain = m_sc->buildOrResize();
const QSize outputSize = m_sc->currentPixelSize();
m_proj = r.r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_proj.translate(0, 0, -4);

View File

@ -441,7 +441,7 @@ void Renderer::init()
{
m_sc = r->newSwapChain();
m_ds = r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(),
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
m_releasePool << m_ds;
@ -543,11 +543,9 @@ void Renderer::render(bool newlyExposed, bool wakeBeforePresent)
auto buildOrResizeSwapChain = [this] {
qDebug() << "renderer" << this << "build or resize swapchain for window" << window;
const QSize outputSize = m_sc->surfacePixelSize();
qDebug() << " size is" << outputSize;
m_ds->setPixelSize(outputSize);
m_ds->build();
m_hasSwapChain = m_sc->buildOrResize();
const QSize outputSize = m_sc->currentPixelSize();
qDebug() << " size is" << outputSize;
m_proj = r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);

View File

@ -58,6 +58,7 @@
#include <QPlatformSurfaceEvent>
#include <QElapsedTimer>
#include <QTimer>
#include <QLoggingCategory>
#include <QtGui/private/qshader_p.h>
#include <QFile>
@ -70,7 +71,6 @@
#endif
#if QT_CONFIG(vulkan)
#include <QLoggingCategory>
#include <QtGui/private/qrhivulkan_p.h>
#endif
@ -307,7 +307,7 @@ void Window::init()
m_sc = m_r->newSwapChain();
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size yet
QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
sampleCount,
QRhiRenderBuffer::UsedWithSwapChainOnly);
m_sc->setWindow(this);
@ -344,16 +344,12 @@ void Window::releaseResources()
void Window::resizeSwapChain()
{
const QSize outputSize = m_sc->surfacePixelSize();
m_ds->setPixelSize(outputSize);
m_ds->build(); // == m_ds->release(); m_ds->build();
m_hasSwapChain = m_sc->buildOrResize();
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
m_frameCount = 0;
m_timer.restart();
const QSize outputSize = m_sc->currentPixelSize();
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_proj.translate(0, 0, -4);
@ -444,6 +440,8 @@ int main(int argc, char **argv)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QLoggingCategory::setFilterRules(QLatin1String("qt.rhi.*=true"));
// Defaults.
#if defined(Q_OS_WIN)
graphicsApi = D3D11;

View File

@ -68,6 +68,8 @@ struct {
QRhiTexture *newTex = nullptr;
QRhiTexture *importedTex = nullptr;
int testStage = 0;
QRhiShaderResourceBinding bindings[2];
} d;
void Window::customInit()
@ -100,10 +102,10 @@ void Window::customInit()
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
});
d.bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
d.ps = m_r->newGraphicsPipeline();
@ -211,9 +213,8 @@ void Window::customRender()
u->copyTexture(d.newTex, d.tex, desc);
// Now replace d.tex with d.newTex as the shader resource.
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
// "rebuild", whatever that means for a given backend. This srb is
// already live as the ps in the setGraphicsPipeline references it,
// but that's fine. Changes will be picked up automatically.
@ -259,9 +260,8 @@ void Window::customRender()
// underneath (owned by d.tex)
// switch to showing d.importedTex
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
} else {
qWarning("Accessing native texture object is not supported");
@ -270,9 +270,8 @@ void Window::customRender()
// Exercise uploading uncompressed data without a QImage.
if (d.testStage == 7) {
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
const QSize sz(221, 139);

View File

@ -94,11 +94,11 @@ void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp)
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
premulAlphaBlend.enable = true;
QVector<QRhiGraphicsPipeline::TargetBlend> rtblends;
QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> rtblends;
for (int i = 0; i < m_colorAttCount; ++i)
rtblends << premulAlphaBlend;
m_ps->setTargetBlends(rtblends);
m_ps->setTargetBlends(rtblends.cbegin(), rtblends.cend());
m_ps->setSampleCount(m_sampleCount);
if (m_depthWrite) { // TriangleOnCube may want to exercise this