Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: I77ba01f09b3dbcaf13cb265a70d9da661c32a61f
This commit is contained in:
commit
4e40c54a3c
@ -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": {
|
"sse2": {
|
||||||
"label": "SSE2 instructions",
|
"label": "SSE2 instructions",
|
||||||
"type": "x86Simd"
|
"type": "x86Simd"
|
||||||
@ -1005,6 +1016,11 @@
|
|||||||
{ "type": "define", "name": "QT_REDUCE_RELOCATIONS" }
|
{ "type": "define", "name": "QT_REDUCE_RELOCATIONS" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"signaling_nan": {
|
||||||
|
"label": "Signaling NaN",
|
||||||
|
"condition": "tests.signaling_nan",
|
||||||
|
"output": [ "publicFeature" ]
|
||||||
|
},
|
||||||
"sse2": {
|
"sse2": {
|
||||||
"label": "SSE2",
|
"label": "SSE2",
|
||||||
"condition": "(arch.i386 || arch.x86_64) && tests.sse2",
|
"condition": "(arch.i386 || arch.x86_64) && tests.sse2",
|
||||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
|||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
#ifndef QT_NO_TRANSLATION
|
#ifndef QT_NO_TRANSLATION
|
||||||
QString translatorFileName = QLatin1String("qt_");
|
QString translatorFileName = QLatin1String("qtbase_");
|
||||||
translatorFileName += QLocale::system().name();
|
translatorFileName += QLocale::system().name();
|
||||||
QTranslator *translator = new QTranslator(&app);
|
QTranslator *translator = new QTranslator(&app);
|
||||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
|||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
#ifndef QT_NO_TRANSLATION
|
#ifndef QT_NO_TRANSLATION
|
||||||
QString translatorFileName = QLatin1String("qt_");
|
QString translatorFileName = QLatin1String("qtbase_");
|
||||||
translatorFileName += QLocale::system().name();
|
translatorFileName += QLocale::system().name();
|
||||||
QTranslator *translator = new QTranslator(&app);
|
QTranslator *translator = new QTranslator(&app);
|
||||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
|||||||
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));
|
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));
|
||||||
|
|
||||||
#ifndef QT_NO_TRANSLATION
|
#ifndef QT_NO_TRANSLATION
|
||||||
QString translatorFileName = QLatin1String("qt_");
|
QString translatorFileName = QLatin1String("qtbase_");
|
||||||
translatorFileName += QLocale::system().name();
|
translatorFileName += QLocale::system().name();
|
||||||
QTranslator *translator = new QTranslator(&app);
|
QTranslator *translator = new QTranslator(&app);
|
||||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||||
|
@ -128,7 +128,7 @@ int main(int argc, char *argv[])
|
|||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
#ifndef QT_NO_TRANSLATION
|
#ifndef QT_NO_TRANSLATION
|
||||||
QString translatorFileName = QLatin1String("qt_");
|
QString translatorFileName = QLatin1String("qtbase_");
|
||||||
translatorFileName += QLocale::system().name();
|
translatorFileName += QLocale::system().name();
|
||||||
QTranslator *translator = new QTranslator(&app);
|
QTranslator *translator = new QTranslator(&app);
|
||||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||||
|
41
mkspecs/devices/linux-imx8-g++/qmake.conf
Normal file
41
mkspecs/devices/linux-imx8-g++/qmake.conf
Normal 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)
|
40
mkspecs/devices/linux-imx8-g++/qplatformdefs.h
Normal file
40
mkspecs/devices/linux-imx8-g++/qplatformdefs.h
Normal 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"
|
@ -992,6 +992,22 @@
|
|||||||
\row \li embed_translations \li Embed the generated translations from
|
\row \li embed_translations \li Embed the generated translations from
|
||||||
\c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
|
\c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
|
||||||
Requires \c lrelease to be set, too. Not set by default.
|
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
|
\endtable
|
||||||
|
|
||||||
When you use the \c debug_and_release option (which is the default under
|
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
|
qmake will process all libraries linked to
|
||||||
by the application and find their meta-information (see
|
by the application and find their meta-information (see
|
||||||
\l{LibDepend}{Library Dependencies} for more info).
|
\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
|
\endtable
|
||||||
|
|
||||||
\note The \c create_prl option is required when \e {building} a
|
\note The \c create_prl option is required when \e {building} a
|
||||||
|
42
src/3rdparty/sqlite/patches/0001-Fix-CVE-2019-16168-in-SQLite.patch
vendored
Normal file
42
src/3rdparty/sqlite/patches/0001-Fix-CVE-2019-16168-in-SQLite.patch
vendored
Normal 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)
|
||||||
|
|
4
src/3rdparty/sqlite/qt_attribution.json
vendored
4
src/3rdparty/sqlite/qt_attribution.json
vendored
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
|
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
|
||||||
"Homepage": "https://www.sqlite.org/",
|
"Homepage": "https://www.sqlite.org/",
|
||||||
"Version": "3.28.0",
|
"Version": "3.29.0",
|
||||||
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3280000.zip",
|
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3290000.zip",
|
||||||
"License": "Public Domain",
|
"License": "Public Domain",
|
||||||
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
|
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
|
||||||
}
|
}
|
||||||
|
7132
src/3rdparty/sqlite/sqlite3.c
vendored
7132
src/3rdparty/sqlite/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
53
src/3rdparty/sqlite/sqlite3.h
vendored
53
src/3rdparty/sqlite/sqlite3.h
vendored
@ -123,9 +123,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.28.0"
|
#define SQLITE_VERSION "3.29.0"
|
||||||
#define SQLITE_VERSION_NUMBER 3028000
|
#define SQLITE_VERSION_NUMBER 3029000
|
||||||
#define SQLITE_SOURCE_ID "2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f83156b50"
|
#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** 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]
|
** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
|
||||||
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
|
** 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]
|
** 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
|
** to test whether a file is at least readable. The SQLITE_ACCESS_READ
|
||||||
** directory.
|
** 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
|
** ^SQLite will always allocate at least mxPathname+1 bytes for the
|
||||||
** output buffer xFullPathname. The exact size of the output buffer
|
** 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:
|
** features include but are not limited to the following:
|
||||||
** <ul>
|
** <ul>
|
||||||
** <li> The [PRAGMA writable_schema=ON] statement.
|
** <li> The [PRAGMA writable_schema=ON] statement.
|
||||||
|
** <li> The [PRAGMA journal_mode=OFF] statement.
|
||||||
** <li> Writes to the [sqlite_dbpage] virtual table.
|
** <li> Writes to the [sqlite_dbpage] virtual table.
|
||||||
** <li> Direct writes to [shadow tables].
|
** <li> Direct writes to [shadow tables].
|
||||||
** </ul>
|
** </ul>
|
||||||
@ -2213,6 +2220,34 @@ struct sqlite3_mem_methods {
|
|||||||
** integer into which is written 0 or 1 to indicate whether the writable_schema
|
** integer into which is written 0 or 1 to indicate whether the writable_schema
|
||||||
** is enabled or disabled following this call.
|
** is enabled or disabled following this call.
|
||||||
** </dd>
|
** </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>
|
** </dl>
|
||||||
*/
|
*/
|
||||||
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
|
#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_RESET_DATABASE 1009 /* int int* */
|
||||||
#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
|
#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
|
||||||
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* 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
|
** 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_SORTER_MMAP 24
|
||||||
#define SQLITE_TESTCTRL_IMPOSTER 25
|
#define SQLITE_TESTCTRL_IMPOSTER 25
|
||||||
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
|
#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
|
** CAPI3REF: SQL Keyword Checking
|
||||||
|
@ -416,7 +416,7 @@ public:
|
|||||||
LoadArchiveMemberHint = 0x04
|
LoadArchiveMemberHint = 0x04
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(LoadHints, LoadHint)
|
Q_DECLARE_FLAGS(LoadHints, LoadHint)
|
||||||
Q_FLAG(LoadHints)
|
Q_FLAG(LoadHint)
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
//! [39]
|
//! [39]
|
||||||
|
@ -109,6 +109,7 @@
|
|||||||
# define QT_FEATURE_renameat2 -1
|
# define QT_FEATURE_renameat2 -1
|
||||||
#endif
|
#endif
|
||||||
#define QT_FEATURE_sharedmemory -1
|
#define QT_FEATURE_sharedmemory -1
|
||||||
|
#define QT_FEATURE_signaling_nan -1
|
||||||
#define QT_FEATURE_slog2 -1
|
#define QT_FEATURE_slog2 -1
|
||||||
#ifdef __GLIBC_PREREQ
|
#ifdef __GLIBC_PREREQ
|
||||||
# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)
|
# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)
|
||||||
|
@ -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); }
|
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.
|
Returns the bit pattern of a signalling NaN as a double.
|
||||||
\relates <QtGlobal>
|
\relates <QtGlobal>
|
||||||
*/
|
*/
|
||||||
Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
|
Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the bit pattern of a quiet NaN as a double.
|
Returns the bit pattern of a quiet NaN as a double.
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
|
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 qIsNaN(double d);
|
||||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(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 qIsNaN(float f);
|
||||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
|
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
|
||||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
|
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();
|
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 qQNaN();
|
||||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
|
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);
|
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
|
||||||
|
|
||||||
#define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
|
#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)())
|
#define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -133,13 +133,14 @@ Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
|
|||||||
return std::numeric_limits<double>::infinity();
|
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_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
|
||||||
{
|
{
|
||||||
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
|
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
|
||||||
"platform has no definition for signaling NaN for type double");
|
"platform has no definition for signaling NaN for type double");
|
||||||
return std::numeric_limits<double>::signaling_NaN();
|
return std::numeric_limits<double>::signaling_NaN();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Quiet NaN
|
// Quiet NaN
|
||||||
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept
|
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept
|
||||||
|
@ -90,47 +90,6 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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 {
|
enum {
|
||||||
// may be "overridden" by a member enum
|
// may be "overridden" by a member enum
|
||||||
FillBufferNoexcept = true
|
FillBufferNoexcept = true
|
||||||
@ -371,8 +330,8 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qsizetype filled = 0;
|
qsizetype filled = 0;
|
||||||
if (qt_has_hwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
|
if (qHasHwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
|
||||||
filled += qt_random_cpu(buffer, count);
|
filled += qRandomCpu(buffer, count);
|
||||||
|
|
||||||
if (filled != count && (uint(qt_randomdevice_control.loadAcquire()) & SkipSystemRNG) == 0) {
|
if (filled != count && (uint(qt_randomdevice_control.loadAcquire()) & SkipSystemRNG) == 0) {
|
||||||
qsizetype bytesFilled =
|
qsizetype bytesFilled =
|
||||||
|
@ -81,14 +81,6 @@ static const struct {
|
|||||||
} qt_randomdevice_control;
|
} qt_randomdevice_control;
|
||||||
#endif
|
#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
|
QT_END_NAMESPACE
|
||||||
|
@ -249,16 +249,18 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
|
|||||||
isSymLink(). The symLinkTarget() function provides the name of the file
|
isSymLink(). The symLinkTarget() function provides the name of the file
|
||||||
the symlink points to.
|
the symlink points to.
|
||||||
|
|
||||||
On Unix (including \macos and iOS), the symlink has the same size() has
|
On Unix (including \macos and iOS), the property getter functions in this
|
||||||
the file it points to, because Unix handles symlinks
|
class return the properties such as times and size of the target file, not
|
||||||
transparently; similarly, opening a symlink using QFile
|
the symlink, because Unix handles symlinks transparently. Opening a symlink
|
||||||
effectively opens the link's target. For example:
|
using QFile effectively opens the link's target. For example:
|
||||||
|
|
||||||
\snippet code/src_corelib_io_qfileinfo.cpp 0
|
\snippet code/src_corelib_io_qfileinfo.cpp 0
|
||||||
|
|
||||||
On Windows, shortcuts are \c .lnk files. The reported size() is that of
|
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
|
||||||
the shortcut (not the link's target), and opening a shortcut using QFile
|
on Unix systems, the property getters return the size of the targeted file,
|
||||||
opens the \c .lnk file. For example:
|
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
|
\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.
|
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
|
\note If the \l{NTFS permissions} check has not been enabled, the result
|
||||||
on Windows will merely reflect whether the file exists.
|
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.
|
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
|
\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.
|
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.
|
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()
|
\sa isReadable(), isWritable(), permission()
|
||||||
*/
|
*/
|
||||||
bool QFileInfo::isExecutable() const
|
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.
|
Returns \c true if this is a `hidden' file; otherwise returns \c false.
|
||||||
|
|
||||||
\b{Note:} This function returns \c true for the special entries
|
\b{Note:} This function returns \c true for the special entries "." and
|
||||||
"." and ".." on Unix, even though QDir::entryList threats them as shown.
|
".." 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
|
bool QFileInfo::isHidden() const
|
||||||
{
|
{
|
||||||
@ -991,6 +1007,9 @@ bool QFileInfo::isNativePath() const
|
|||||||
link to a file. Returns \c false if the
|
link to a file. Returns \c false if the
|
||||||
object points to something which isn't a file, such as a directory.
|
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()
|
\sa isDir(), isSymLink(), isBundle()
|
||||||
*/
|
*/
|
||||||
bool QFileInfo::isFile() const
|
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
|
Returns \c true if this object points to a directory or to a symbolic
|
||||||
link to a directory; otherwise returns \c false.
|
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()
|
\sa isFile(), isSymLink(), isBundle()
|
||||||
*/
|
*/
|
||||||
bool QFileInfo::isDir() const
|
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
|
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.
|
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()
|
\sa isDir(), isSymLink(), isFile()
|
||||||
*/
|
*/
|
||||||
bool QFileInfo::isBundle() const
|
bool QFileInfo::isBundle() const
|
||||||
@ -1044,7 +1069,8 @@ bool QFileInfo::isBundle() const
|
|||||||
the \l{symLinkTarget()}{link's target}.
|
the \l{symLinkTarget()}{link's target}.
|
||||||
|
|
||||||
In addition, true will be returned for shortcuts (\c *.lnk files) on
|
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:
|
Example:
|
||||||
|
|
||||||
@ -1190,6 +1216,9 @@ QString QFileInfo::symLinkTarget() const
|
|||||||
milliseconds). On Windows, it will return an empty string unless
|
milliseconds). On Windows, it will return an empty string unless
|
||||||
the \l{NTFS permissions} check has been enabled.
|
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()
|
\sa ownerId(), group(), groupId()
|
||||||
*/
|
*/
|
||||||
QString QFileInfo::owner() const
|
QString QFileInfo::owner() const
|
||||||
@ -1206,6 +1235,9 @@ QString QFileInfo::owner() const
|
|||||||
On Windows and on systems where files do not have owners this
|
On Windows and on systems where files do not have owners this
|
||||||
function returns ((uint) -2).
|
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()
|
\sa owner(), group(), groupId()
|
||||||
*/
|
*/
|
||||||
uint QFileInfo::ownerId() const
|
uint QFileInfo::ownerId() const
|
||||||
@ -1225,6 +1257,9 @@ uint QFileInfo::ownerId() const
|
|||||||
This function can be time consuming under Unix (in the order of
|
This function can be time consuming under Unix (in the order of
|
||||||
milliseconds).
|
milliseconds).
|
||||||
|
|
||||||
|
If the file is a symlink, this function returns the owning group of the
|
||||||
|
target (not the symlink).
|
||||||
|
|
||||||
\sa groupId(), owner(), ownerId()
|
\sa groupId(), owner(), ownerId()
|
||||||
*/
|
*/
|
||||||
QString QFileInfo::group() const
|
QString QFileInfo::group() const
|
||||||
@ -1241,6 +1276,9 @@ QString QFileInfo::group() const
|
|||||||
On Windows and on systems where files do not have groups this
|
On Windows and on systems where files do not have groups this
|
||||||
function always returns (uint) -2.
|
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()
|
\sa group(), owner(), ownerId()
|
||||||
*/
|
*/
|
||||||
uint QFileInfo::groupId() const
|
uint QFileInfo::groupId() const
|
||||||
@ -1266,6 +1304,9 @@ uint QFileInfo::groupId() const
|
|||||||
Example:
|
Example:
|
||||||
\snippet code/src_corelib_io_qfileinfo.cpp 10
|
\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()
|
\sa isReadable(), isWritable(), isExecutable()
|
||||||
*/
|
*/
|
||||||
bool QFileInfo::permission(QFile::Permissions permissions) const
|
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
|
\note The result might be inaccurate on Windows if the
|
||||||
\l{NTFS permissions} check has not been enabled.
|
\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
|
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
|
Returns the file size in bytes. If the file does not exist or cannot be
|
||||||
fetched, 0 is returned.
|
fetched, 0 is returned.
|
||||||
|
|
||||||
|
If the file is a symlink, the size of the target file is returned
|
||||||
|
(not the symlink).
|
||||||
|
|
||||||
\sa exists()
|
\sa exists()
|
||||||
*/
|
*/
|
||||||
qint64 QFileInfo::size() const
|
qint64 QFileInfo::size() const
|
||||||
@ -1334,6 +1381,9 @@ qint64 QFileInfo::size() const
|
|||||||
the time the file was created, metadataChangeTime() to get the time its
|
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.
|
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()
|
\sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::created() const
|
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
|
If the file birth time is not available, this function returns an invalid
|
||||||
QDateTime.
|
QDateTime.
|
||||||
|
|
||||||
|
If the file is a symlink, the time of the target file is returned
|
||||||
|
(not the symlink).
|
||||||
|
|
||||||
\sa lastModified(), lastRead(), metadataChangeTime()
|
\sa lastModified(), lastRead(), metadataChangeTime()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::birthTime() const
|
QDateTime QFileInfo::birthTime() const
|
||||||
@ -1366,6 +1419,9 @@ QDateTime QFileInfo::birthTime() const
|
|||||||
user writes or sets inode information (for example, changing the file
|
user writes or sets inode information (for example, changing the file
|
||||||
permissions).
|
permissions).
|
||||||
|
|
||||||
|
If the file is a symlink, the time of the target file is returned
|
||||||
|
(not the symlink).
|
||||||
|
|
||||||
\sa lastModified(), lastRead()
|
\sa lastModified(), lastRead()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::metadataChangeTime() const
|
QDateTime QFileInfo::metadataChangeTime() const
|
||||||
@ -1376,6 +1432,9 @@ QDateTime QFileInfo::metadataChangeTime() const
|
|||||||
/*!
|
/*!
|
||||||
Returns the date and local time when the file was last modified.
|
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()
|
\sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::lastModified() const
|
QDateTime QFileInfo::lastModified() const
|
||||||
@ -1389,6 +1448,9 @@ QDateTime QFileInfo::lastModified() const
|
|||||||
On platforms where this information is not available, returns the
|
On platforms where this information is not available, returns the
|
||||||
same as lastModified().
|
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()
|
\sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::lastRead() const
|
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
|
Returns the file time specified by \a time. If the time cannot be
|
||||||
determined, an invalid date time is returned.
|
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()
|
\sa QFile::FileTime, QDateTime::isValid()
|
||||||
*/
|
*/
|
||||||
QDateTime QFileInfo::fileTime(QFile::FileTime time) const
|
QDateTime QFileInfo::fileTime(QFile::FileTime time) const
|
||||||
|
@ -69,7 +69,9 @@ static bool checkNameDecodable(const char *d_name, qsizetype len)
|
|||||||
# ifdef QT_LOCALE_IS_UTF8
|
# ifdef QT_LOCALE_IS_UTF8
|
||||||
int mibEnum = 106;
|
int mibEnum = 106;
|
||||||
# else
|
# else
|
||||||
int mibEnum = codec->mibEnum();
|
int mibEnum = 4; // Latin 1
|
||||||
|
if (codec)
|
||||||
|
mibEnum = codec->mibEnum();
|
||||||
# endif
|
# endif
|
||||||
if (Q_LIKELY(mibEnum == 106)) // UTF-8
|
if (Q_LIKELY(mibEnum == 106)) // UTF-8
|
||||||
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;
|
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;
|
||||||
|
@ -423,7 +423,7 @@ bool QEventDispatcherCoreFoundation::processPostedEvents()
|
|||||||
m_processEvents.processedPostedEvents = true;
|
m_processEvents.processedPostedEvents = true;
|
||||||
|
|
||||||
qCDebug(lcEventDispatcher) << "Sending posted events for"
|
qCDebug(lcEventDispatcher) << "Sending posted events for"
|
||||||
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
|
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
|
||||||
QCoreApplication::sendPostedEvents();
|
QCoreApplication::sendPostedEvents();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -376,6 +376,38 @@ static quint64 detectProcessorFeatures()
|
|||||||
features &= ~AllAVX512;
|
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;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,4 +622,40 @@ void qDumpCPUFeatures()
|
|||||||
puts("");
|
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
|
QT_END_NAMESPACE
|
||||||
|
@ -346,6 +346,15 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
|
|||||||
#endif
|
#endif
|
||||||
Q_CORE_EXPORT quint64 qDetectCpuFeatures();
|
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()
|
static inline quint64 qCpuFeatures()
|
||||||
{
|
{
|
||||||
quint64 features = qt_cpu_features[0].loadRelaxed();
|
quint64 features = qt_cpu_features[0].loadRelaxed();
|
||||||
@ -362,6 +371,15 @@ static inline quint64 qCpuFeatures()
|
|||||||
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|
||||||
|| ((qCpuFeatures() & 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) \
|
#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)
|
for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public:
|
|||||||
|
|
||||||
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
|
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
|
||||||
{
|
{
|
||||||
resize(list.size());
|
resize(int(list.size())); // ### q6sizetype
|
||||||
std::copy(list.begin(), list.end(),
|
std::copy(list.begin(), list.end(),
|
||||||
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
|
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
@ -54,7 +55,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
|
Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
|
||||||
|
|
||||||
#ifndef GL_CONTEXT_LOST
|
#ifndef GL_CONTEXT_LOST
|
||||||
#define GL_CONTEXT_LOST 0x0507
|
#define GL_CONTEXT_LOST 0x0507
|
||||||
@ -64,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
|
|||||||
#define GL_PROGRAM_BINARY_LENGTH 0x8741
|
#define GL_PROGRAM_BINARY_LENGTH 0x8741
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
|
||||||
|
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
|
||||||
|
#endif
|
||||||
|
|
||||||
const quint32 BINSHADER_MAGIC = 0x5174;
|
const quint32 BINSHADER_MAGIC = 0x5174;
|
||||||
const quint32 BINSHADER_VERSION = 0x3;
|
const quint32 BINSHADER_VERSION = 0x3;
|
||||||
const quint32 BINSHADER_QTVERSION = QT_VERSION;
|
const quint32 BINSHADER_QTVERSION = QT_VERSION;
|
||||||
@ -123,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
|
|||||||
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
|
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
|
||||||
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
|
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
|
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
|
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
|
||||||
{
|
{
|
||||||
if (buf.size() < BASE_HEADER_SIZE) {
|
if (buf.size() < BASE_HEADER_SIZE) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Cached size too small");
|
qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
|
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
|
||||||
if (readUInt(&p) != BINSHADER_MAGIC) {
|
if (readUInt(&p) != BINSHADER_MAGIC) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Magic does not match");
|
qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (readUInt(&p) != BINSHADER_VERSION) {
|
if (readUInt(&p) != BINSHADER_VERSION) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Version does not match");
|
qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (readUInt(&p) != BINSHADER_QTVERSION) {
|
if (readUInt(&p) != BINSHADER_QTVERSION) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
|
qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (readUInt(&p) != sizeof(quintptr)) {
|
if (readUInt(&p) != sizeof(quintptr)) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
|
qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -196,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
|
|||||||
|
|
||||||
GLenum err = funcs->glGetError();
|
GLenum err = funcs->glGetError();
|
||||||
if (err != GL_NO_ERROR) {
|
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",
|
"format 0x%x, err = 0x%x",
|
||||||
programId, blobSize, blobFormat, err);
|
programId, blobSize, blobFormat, err);
|
||||||
return false;
|
return false;
|
||||||
@ -204,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
|
|||||||
GLint linkStatus = 0;
|
GLint linkStatus = 0;
|
||||||
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
|
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
|
||||||
if (linkStatus != GL_TRUE) {
|
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",
|
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
|
||||||
programId, blobSize, blobFormat, linkStatus, err);
|
programId, blobSize, blobFormat, linkStatus, err);
|
||||||
return false;
|
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);
|
programId, blobSize, blobFormat, err);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -318,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
|
|||||||
if (vendor != info.glvendor) {
|
if (vendor != info.glvendor) {
|
||||||
// readStr returns non-null terminated strings just pointing to inside
|
// readStr returns non-null terminated strings just pointing to inside
|
||||||
// 'p' so must print these via the stream qCDebug and not constData().
|
// '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();
|
undertaker.setActive();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray renderer = readStr(&p);
|
QByteArray renderer = readStr(&p);
|
||||||
if (renderer != info.glrenderer) {
|
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();
|
undertaker.setActive();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray version = readStr(&p);
|
QByteArray version = readStr(&p);
|
||||||
if (version != info.glversion) {
|
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();
|
undertaker.setActive();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -383,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
|||||||
|
|
||||||
const int totalSize = headerSize + paddingSize + blobSize;
|
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)
|
if (!blobSize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -417,7 +422,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
|||||||
#endif
|
#endif
|
||||||
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
|
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
|
||||||
if (blobSize != outSize) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
|||||||
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
if (f.write(blob) < blob.length())
|
if (f.write(blob) < blob.length())
|
||||||
#endif
|
#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 {
|
} 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
|
#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
|
QT_END_NAMESPACE
|
||||||
|
@ -52,21 +52,26 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <QtGui/qtguiglobal.h>
|
#include <QtGui/qtguiglobal.h>
|
||||||
#include <QtGui/qopenglshaderprogram.h>
|
|
||||||
#include <QtCore/qcache.h>
|
#include <QtCore/qcache.h>
|
||||||
#include <QtCore/qmutex.h>
|
#include <QtCore/qmutex.h>
|
||||||
|
#include <QtGui/private/qopenglcontext_p.h>
|
||||||
|
#include <QtGui/private/qshader_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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
|
class QOpenGLProgramBinaryCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct ShaderDesc {
|
struct ShaderDesc {
|
||||||
ShaderDesc() { }
|
ShaderDesc() { }
|
||||||
ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
|
ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
|
||||||
: type(type), source(source)
|
: stage(stage), source(source)
|
||||||
{ }
|
{ }
|
||||||
QOpenGLShader::ShaderType type;
|
QShader::Stage stage;
|
||||||
QByteArray source;
|
QByteArray source;
|
||||||
};
|
};
|
||||||
struct ProgramDesc {
|
struct ProgramDesc {
|
||||||
@ -104,6 +109,36 @@ private:
|
|||||||
QMutex m_mutex;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
#include <QtCore/qvarlengtharray.h>
|
#include <QtCore/qvarlengtharray.h>
|
||||||
#include <QtCore/qvector.h>
|
#include <QtCore/qvector.h>
|
||||||
#include <QtCore/qloggingcategory.h>
|
#include <QtCore/qloggingcategory.h>
|
||||||
#include <QtCore/qcoreapplication.h>
|
|
||||||
#include <QtGui/qtransform.h>
|
#include <QtGui/qtransform.h>
|
||||||
#include <QtGui/QColor>
|
#include <QtGui/QColor>
|
||||||
#include <QtGui/QSurfaceFormat>
|
#include <QtGui/QSurfaceFormat>
|
||||||
@ -178,7 +177,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
|
(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
|
// For GLES 3.1/3.2
|
||||||
#ifndef GL_GEOMETRY_SHADER
|
#ifndef GL_GEOMETRY_SHADER
|
||||||
@ -209,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
|
|||||||
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
|
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
|
|
||||||
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef QT_OPENGL_ES_2
|
#ifndef QT_OPENGL_ES_2
|
||||||
static inline bool isFormatGLES(const QSurfaceFormat &f)
|
static inline bool isFormatGLES(const QSurfaceFormat &f)
|
||||||
{
|
{
|
||||||
@ -1080,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
|
|||||||
return addCacheableShaderFromSourceCode(type, QByteArray(source));
|
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
|
\overload
|
||||||
|
|
||||||
@ -1108,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
|
|||||||
if (d->isCacheDisabled())
|
if (d->isCacheDisabled())
|
||||||
return addShaderFromSourceCode(type, source);
|
return addShaderFromSourceCode(type, source);
|
||||||
|
|
||||||
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
|
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
|
|||||||
if (d->isCacheDisabled())
|
if (d->isCacheDisabled())
|
||||||
return addShaderFromSourceFile(type, fileName);
|
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
|
// 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
|
// hash the filename as the cache key, perhaps combined with last-modified
|
||||||
// timestamp checks. However, this would raise a number of issues (no
|
// timestamp checks. However, this would raise a number of issues (no
|
||||||
@ -3719,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
|
|||||||
return true;
|
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
|
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
|
||||||
{
|
{
|
||||||
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
|
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
|
||||||
@ -3800,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
|
|||||||
{
|
{
|
||||||
Q_Q(QOpenGLShaderProgram);
|
Q_Q(QOpenGLShaderProgram);
|
||||||
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
|
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)) {
|
if (!s->compileSourceCode(shader.source)) {
|
||||||
log = s->log();
|
log = s->log();
|
||||||
return false;
|
return false;
|
||||||
@ -3819,19 +3781,19 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
|
|||||||
Q_Q(QOpenGLShaderProgram);
|
Q_Q(QOpenGLShaderProgram);
|
||||||
|
|
||||||
const QByteArray cacheKey = binaryProgram.cacheKey();
|
const QByteArray cacheKey = binaryProgram.cacheKey();
|
||||||
if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
|
if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
|
||||||
qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
|
qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
|
||||||
binaryProgram.shaders.count(), cacheKey.constData());
|
binaryProgram.shaders.count(), cacheKey.constData());
|
||||||
|
|
||||||
bool needsCompile = true;
|
bool needsCompile = true;
|
||||||
if (binCache.load(cacheKey, q->programId())) {
|
if (binCache.load(cacheKey, q->programId())) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
|
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
|
||||||
needsCompile = false;
|
needsCompile = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsSave = false;
|
bool needsSave = false;
|
||||||
if (needsCompile) {
|
if (needsCompile) {
|
||||||
qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
|
qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
|
||||||
if (compileCacheable())
|
if (compileCacheable())
|
||||||
needsSave = true;
|
needsSave = true;
|
||||||
else
|
else
|
||||||
|
@ -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
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
@ -207,3 +221,5 @@ const BYTE g_killDeviceByTimingOut[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
|
#endif // CS_TDR_P_H
|
@ -1981,6 +1981,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const
|
|||||||
How the renderbuffer is implemented by a backend is not exposed to the
|
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
|
applications. In some cases it may be backed by ordinary textures, while in
|
||||||
others there may be a different kind of native resource used.
|
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()
|
Flag values for flags() and setFlags()
|
||||||
|
|
||||||
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
|
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
|
||||||
that the renderbuffer is only used in combination with a QRhiSwapChain and
|
that the renderbuffer is only used in combination with a QRhiSwapChain, and
|
||||||
never in other ways. Relevant with some backends, while others ignore it.
|
never in any other way. This provides automatic sizing and resource
|
||||||
With OpenGL where a separate windowing system interface API is in use (EGL,
|
rebuilding, so calling setPixelSize() or build() is not needed whenever
|
||||||
GLX, etc.), the flag is important since it avoids creating any actual
|
this flag is set. This flag value may also trigger backend-specific
|
||||||
resource as there is already a windowing system provided depth/stencil
|
behavior, for example with OpenGL, where a separate windowing system
|
||||||
buffer as requested by QSurfaceFormat.
|
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
|
be used with the same pipeline, assuming the pipeline was built with one of
|
||||||
them in the first place.
|
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
|
\badcode
|
||||||
srb2 = rhi->newShaderResourceBindings();
|
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->setGraphicsPipeline(ps);
|
||||||
cb->setShaderResources(srb2); // binds srb2
|
cb->setShaderResources(srb2); // binds srb2
|
||||||
@ -2634,43 +2637,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
|
|||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
|
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
|
||||||
: d(new QRhiShaderResourceBindingPrivate)
|
|
||||||
{
|
{
|
||||||
}
|
// Zero out everything, including possible padding, because will use
|
||||||
|
// qHashBits on it.
|
||||||
/*!
|
memset(&d.u, 0, sizeof(d.u));
|
||||||
\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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2687,8 +2657,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
|
|||||||
*/
|
*/
|
||||||
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
|
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
|
||||||
{
|
{
|
||||||
return (d == other.d)
|
return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
|
||||||
|| (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)
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b;
|
QRhiShaderResourceBinding b;
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.binding = binding;
|
||||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
b.d.stage = stage;
|
||||||
d->binding = binding;
|
b.d.type = UniformBuffer;
|
||||||
d->stage = stage;
|
b.d.u.ubuf.buf = buf;
|
||||||
d->type = UniformBuffer;
|
b.d.u.ubuf.offset = 0;
|
||||||
d->u.ubuf.buf = buf;
|
b.d.u.ubuf.maybeSize = 0; // entire buffer
|
||||||
d->u.ubuf.offset = 0;
|
b.d.u.ubuf.hasDynamicOffset = false;
|
||||||
d->u.ubuf.maybeSize = 0; // entire buffer
|
|
||||||
d->u.ubuf.hasDynamicOffset = false;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2730,9 +2697,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
|||||||
{
|
{
|
||||||
Q_ASSERT(size > 0);
|
Q_ASSERT(size > 0);
|
||||||
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
|
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.u.ubuf.offset = offset;
|
||||||
d->u.ubuf.offset = offset;
|
b.d.u.ubuf.maybeSize = size;
|
||||||
d->u.ubuf.maybeSize = size;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2751,8 +2717,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
|
|||||||
int binding, StageFlags stage, QRhiBuffer *buf, int size)
|
int binding, StageFlags stage, QRhiBuffer *buf, int size)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
|
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.u.ubuf.hasDynamicOffset = true;
|
||||||
d->u.ubuf.hasDynamicOffset = true;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2765,13 +2730,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
|
|||||||
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
|
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b;
|
QRhiShaderResourceBinding b;
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.binding = binding;
|
||||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
b.d.stage = stage;
|
||||||
d->binding = binding;
|
b.d.type = SampledTexture;
|
||||||
d->stage = stage;
|
b.d.u.stex.tex = tex;
|
||||||
d->type = SampledTexture;
|
b.d.u.stex.sampler = sampler;
|
||||||
d->u.stex.tex = tex;
|
|
||||||
d->u.stex.sampler = sampler;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2787,13 +2750,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
|
|||||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b;
|
QRhiShaderResourceBinding b;
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.binding = binding;
|
||||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
b.d.stage = stage;
|
||||||
d->binding = binding;
|
b.d.type = ImageLoad;
|
||||||
d->stage = stage;
|
b.d.u.simage.tex = tex;
|
||||||
d->type = ImageLoad;
|
b.d.u.simage.level = level;
|
||||||
d->u.simage.tex = tex;
|
|
||||||
d->u.simage.level = level;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2809,8 +2770,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
|
|||||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.type = ImageStore;
|
||||||
d->type = ImageStore;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2826,8 +2786,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
|
|||||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.type = ImageLoadStore;
|
||||||
d->type = ImageLoadStore;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2841,14 +2800,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
|||||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b;
|
QRhiShaderResourceBinding b;
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.binding = binding;
|
||||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
b.d.stage = stage;
|
||||||
d->binding = binding;
|
b.d.type = BufferLoad;
|
||||||
d->stage = stage;
|
b.d.u.sbuf.buf = buf;
|
||||||
d->type = BufferLoad;
|
b.d.u.sbuf.offset = 0;
|
||||||
d->u.sbuf.buf = buf;
|
b.d.u.sbuf.maybeSize = 0; // entire buffer
|
||||||
d->u.sbuf.offset = 0;
|
|
||||||
d->u.sbuf.maybeSize = 0; // entire buffer
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2864,9 +2821,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
|||||||
{
|
{
|
||||||
Q_ASSERT(size > 0);
|
Q_ASSERT(size > 0);
|
||||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.u.sbuf.offset = offset;
|
||||||
d->u.sbuf.offset = offset;
|
b.d.u.sbuf.maybeSize = size;
|
||||||
d->u.sbuf.maybeSize = size;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2880,8 +2836,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
|||||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.type = BufferStore;
|
||||||
d->type = BufferStore;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2897,9 +2852,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
|||||||
{
|
{
|
||||||
Q_ASSERT(size > 0);
|
Q_ASSERT(size > 0);
|
||||||
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
|
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.u.sbuf.offset = offset;
|
||||||
d->u.sbuf.offset = offset;
|
b.d.u.sbuf.maybeSize = size;
|
||||||
d->u.sbuf.maybeSize = size;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2913,8 +2867,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
|||||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.type = BufferLoadStore;
|
||||||
d->type = BufferLoadStore;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2930,9 +2883,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
|||||||
{
|
{
|
||||||
Q_ASSERT(size > 0);
|
Q_ASSERT(size > 0);
|
||||||
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
|
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
b.d.u.sbuf.offset = offset;
|
||||||
d->u.sbuf.offset = offset;
|
b.d.u.sbuf.maybeSize = size;
|
||||||
d->u.sbuf.maybeSize = size;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2948,28 +2900,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
|||||||
*/
|
*/
|
||||||
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
|
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;
|
return true;
|
||||||
|
|
||||||
if (a.d->binding != b.d->binding
|
|
||||||
|| a.d->stage != b.d->stage
|
if (da->binding != db->binding
|
||||||
|| a.d->type != b.d->type)
|
|| da->stage != db->stage
|
||||||
|
|| da->type != db->type)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (a.d->type) {
|
switch (da->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
if (a.d->u.ubuf.buf != b.d->u.ubuf.buf
|
if (da->u.ubuf.buf != db->u.ubuf.buf
|
||||||
|| a.d->u.ubuf.offset != b.d->u.ubuf.offset
|
|| da->u.ubuf.offset != db->u.ubuf.offset
|
||||||
|| a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize)
|
|| da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QRhiShaderResourceBinding::SampledTexture:
|
case QRhiShaderResourceBinding::SampledTexture:
|
||||||
if (a.d->u.stex.tex != b.d->u.stex.tex
|
if (da->u.stex.tex != db->u.stex.tex
|
||||||
|| a.d->u.stex.sampler != b.d->u.stex.sampler)
|
|| da->u.stex.sampler != db->u.stex.sampler)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2979,8 +2935,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
|||||||
case QRhiShaderResourceBinding::ImageStore:
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
Q_FALLTHROUGH();
|
Q_FALLTHROUGH();
|
||||||
case QRhiShaderResourceBinding::ImageLoadStore:
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
if (a.d->u.simage.tex != b.d->u.simage.tex
|
if (da->u.simage.tex != db->u.simage.tex
|
||||||
|| a.d->u.simage.level != b.d->u.simage.level)
|
|| da->u.simage.level != db->u.simage.level)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2990,9 +2946,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
|||||||
case QRhiShaderResourceBinding::BufferStore:
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
Q_FALLTHROUGH();
|
Q_FALLTHROUGH();
|
||||||
case QRhiShaderResourceBinding::BufferLoadStore:
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
|
if (da->u.sbuf.buf != db->u.sbuf.buf
|
||||||
|| a.d->u.sbuf.offset != b.d->u.sbuf.offset
|
|| da->u.sbuf.offset != db->u.sbuf.offset
|
||||||
|| a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
|
|| da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3023,16 +2979,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
|||||||
*/
|
*/
|
||||||
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
|
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
const char *u = reinterpret_cast<const char *>(&b.d->u);
|
const QRhiShaderResourceBinding::Data *d = b.data();
|
||||||
return seed + uint(b.d->binding) + 10 * uint(b.d->stage) + 100 * uint(b.d->type)
|
return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type)
|
||||||
+ qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed);
|
+ qHashBits(&d->u, sizeof(d->u), seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
||||||
{
|
{
|
||||||
const QRhiShaderResourceBindingPrivate *d = b.d;
|
|
||||||
QDebugStateSaver saver(dbg);
|
QDebugStateSaver saver(dbg);
|
||||||
|
const QRhiShaderResourceBinding::Data *d = b.data();
|
||||||
dbg.nospace() << "QRhiShaderResourceBinding("
|
dbg.nospace() << "QRhiShaderResourceBinding("
|
||||||
<< "binding=" << d->binding
|
<< "binding=" << d->binding
|
||||||
<< " stage=" << d->stage
|
<< " stage=" << d->stage
|
||||||
@ -3100,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#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)
|
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
QDebugStateSaver saver(dbg);
|
||||||
@ -3351,7 +3312,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
|
|||||||
{
|
{
|
||||||
sc = rhi->newSwapChain();
|
sc = rhi->newSwapChain();
|
||||||
ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
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,
|
1,
|
||||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||||
sc->setWindow(window);
|
sc->setWindow(window);
|
||||||
@ -3363,9 +3324,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
|
|||||||
|
|
||||||
void resizeSwapChain()
|
void resizeSwapChain()
|
||||||
{
|
{
|
||||||
const QSize outputSize = sc->surfacePixelSize();
|
|
||||||
ds->setPixelSize(outputSize);
|
|
||||||
ds->build();
|
|
||||||
hasSwapChain = sc->buildOrResize();
|
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
|
\return The size of the window's associated surface or layer. Do not assume
|
||||||
this is the same as QWindow::size() * QWindow::devicePixelRatio().
|
this is the same as QWindow::size() * QWindow::devicePixelRatio().
|
||||||
|
|
||||||
Can be called before buildOrResize() (but with window() already set), which
|
\note Can also be called before buildOrResize(), if at least window() is
|
||||||
allows setting the correct size for the depth-stencil buffer that is then
|
already set) This in combination with currentPixelSize() allows to detect
|
||||||
used together with the swapchain's color buffers. Also used in combination
|
when a swapchain needs to be resized. However, watch out for the fact that
|
||||||
with currentPixelSize() to detect size changes.
|
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()
|
\sa currentPixelSize()
|
||||||
*/
|
*/
|
||||||
@ -5541,7 +5513,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
|
|||||||
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
|
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
|
||||||
const UsageState &state)
|
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 != m_buffers.end()) {
|
||||||
if (it->access != *access) {
|
if (it->access != *access) {
|
||||||
const QByteArray name = buf->name();
|
const QByteArray name = buf->name();
|
||||||
@ -5557,12 +5529,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc
|
|||||||
}
|
}
|
||||||
|
|
||||||
Buffer b;
|
Buffer b;
|
||||||
b.buf = buf;
|
|
||||||
b.slot = slot;
|
b.slot = slot;
|
||||||
b.access = *access;
|
b.access = *access;
|
||||||
b.stage = *stage;
|
b.stage = *stage;
|
||||||
b.stateAtPassBegin = state; // first use -> initial state
|
b.stateAtPassBegin = state; // first use -> initial state
|
||||||
m_buffers.append(b);
|
m_buffers.insert(buf, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
|
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,
|
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
|
||||||
const UsageState &state)
|
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 != m_textures.end()) {
|
||||||
if (it->access != *access) {
|
if (it->access != *access) {
|
||||||
// Different subresources of a texture may be used for both load
|
// Different subresources of a texture may be used for both load
|
||||||
@ -5605,11 +5576,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
|
|||||||
}
|
}
|
||||||
|
|
||||||
Texture t;
|
Texture t;
|
||||||
t.tex = tex;
|
|
||||||
t.access = *access;
|
t.access = *access;
|
||||||
t.stage = *stage;
|
t.stage = *stage;
|
||||||
t.stateAtPassBegin = state; // first use -> initial state
|
t.stateAtPassBegin = state; // first use -> initial state
|
||||||
m_textures.append(t);
|
m_textures.insert(tex, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
|
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QVarLengthArray>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@ -320,10 +321,6 @@ public:
|
|||||||
Q_DECLARE_FLAGS(StageFlags, StageFlag)
|
Q_DECLARE_FLAGS(StageFlags, StageFlag)
|
||||||
|
|
||||||
QRhiShaderResourceBinding();
|
QRhiShaderResourceBinding();
|
||||||
QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
|
|
||||||
QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
|
|
||||||
~QRhiShaderResourceBinding();
|
|
||||||
void detach();
|
|
||||||
|
|
||||||
bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
|
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);
|
||||||
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
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:
|
private:
|
||||||
QRhiShaderResourceBindingPrivate *d;
|
Data 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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
|
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 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;
|
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:
|
public:
|
||||||
QRhiResource::Type resourceType() const override;
|
QRhiResource::Type resourceType() const override;
|
||||||
|
|
||||||
QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
|
void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
|
||||||
void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
|
|
||||||
|
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;
|
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
|
||||||
|
|
||||||
@ -909,7 +950,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QRhiShaderResourceBindings(QRhiImplementation *rhi);
|
QRhiShaderResourceBindings(QRhiImplementation *rhi);
|
||||||
QVector<QRhiShaderResourceBinding> m_bindings;
|
QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
|
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
|
||||||
#endif
|
#endif
|
||||||
@ -1040,8 +1081,15 @@ public:
|
|||||||
FrontFace frontFace() const { return m_frontFace; }
|
FrontFace frontFace() const { return m_frontFace; }
|
||||||
void setFrontFace(FrontFace f) { m_frontFace = f; }
|
void setFrontFace(FrontFace f) { m_frontFace = f; }
|
||||||
|
|
||||||
QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
|
void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
|
||||||
void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
|
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; }
|
bool hasDepthTest() const { return m_depthTest; }
|
||||||
void setDepthTest(bool enable) { m_depthTest = enable; }
|
void setDepthTest(bool enable) { m_depthTest = enable; }
|
||||||
@ -1073,8 +1121,19 @@ public:
|
|||||||
float lineWidth() const { return m_lineWidth; }
|
float lineWidth() const { return m_lineWidth; }
|
||||||
void setLineWidth(float width) { m_lineWidth = width; }
|
void setLineWidth(float width) { m_lineWidth = width; }
|
||||||
|
|
||||||
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
|
void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
|
||||||
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
|
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; }
|
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
|
||||||
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
|
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
|
||||||
@ -1093,7 +1152,7 @@ protected:
|
|||||||
Topology m_topology = Triangles;
|
Topology m_topology = Triangles;
|
||||||
CullMode m_cullMode = None;
|
CullMode m_cullMode = None;
|
||||||
FrontFace m_frontFace = CCW;
|
FrontFace m_frontFace = CCW;
|
||||||
QVector<TargetBlend> m_targetBlends;
|
QVarLengthArray<TargetBlend, 8> m_targetBlends;
|
||||||
bool m_depthTest = false;
|
bool m_depthTest = false;
|
||||||
bool m_depthWrite = false;
|
bool m_depthWrite = false;
|
||||||
CompareOp m_depthOp = Less;
|
CompareOp m_depthOp = Less;
|
||||||
@ -1104,7 +1163,7 @@ protected:
|
|||||||
quint32 m_stencilWriteMask = 0xFF;
|
quint32 m_stencilWriteMask = 0xFF;
|
||||||
int m_sampleCount = 1;
|
int m_sampleCount = 1;
|
||||||
float m_lineWidth = 1.0f;
|
float m_lineWidth = 1.0f;
|
||||||
QVector<QRhiShaderStage> m_shaderStages;
|
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
|
||||||
QRhiVertexInputLayout m_vertexInputLayout;
|
QRhiVertexInputLayout m_vertexInputLayout;
|
||||||
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
||||||
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
|
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
|
||||||
|
@ -381,57 +381,6 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL
|
|||||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, 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>
|
template<typename T>
|
||||||
struct QRhiBatchedBindings
|
struct QRhiBatchedBindings
|
||||||
{
|
{
|
||||||
@ -554,28 +503,32 @@ public:
|
|||||||
const UsageState &state);
|
const UsageState &state);
|
||||||
|
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
QRhiBuffer *buf;
|
|
||||||
int slot;
|
int slot;
|
||||||
BufferAccess access;
|
BufferAccess access;
|
||||||
BufferStage stage;
|
BufferStage stage;
|
||||||
UsageState stateAtPassBegin;
|
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 {
|
struct Texture {
|
||||||
QRhiTexture *tex;
|
|
||||||
TextureAccess access;
|
TextureAccess access;
|
||||||
TextureStage stage;
|
TextureStage stage;
|
||||||
UsageState stateAtPassBegin;
|
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 BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||||
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
|
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<Buffer> m_buffers;
|
QHash<QRhiBuffer *, Buffer> m_buffers;
|
||||||
QVector<Texture> m_textures;
|
QHash<QRhiTexture *, Texture> m_textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#include "qrhid3d11_p_p.h"
|
#include "qrhid3d11_p_p.h"
|
||||||
#include "qshader_p.h"
|
#include "qshader_p.h"
|
||||||
#include "cs_tdr.h"
|
#include "cs_tdr_p.h"
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QOperatingSystemVersion>
|
#include <QOperatingSystemVersion>
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
@ -598,7 +598,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
bool hasDynamicOffsetInSrb = false;
|
bool hasDynamicOffsetInSrb = false;
|
||||||
bool srbUpdate = false;
|
bool srbUpdate = false;
|
||||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
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]);
|
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
@ -1746,7 +1746,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
|||||||
srbD->csUAVs.clear();
|
srbD->csUAVs.clear();
|
||||||
|
|
||||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
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]);
|
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
@ -3082,11 +3082,11 @@ bool QD3D11ShaderResourceBindings::build()
|
|||||||
if (!sortedBindings.isEmpty())
|
if (!sortedBindings.isEmpty())
|
||||||
release();
|
release();
|
||||||
|
|
||||||
sortedBindings = m_bindings;
|
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
[](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());
|
boundResourceData.resize(sortedBindings.count());
|
||||||
@ -3939,9 +3939,16 @@ bool QD3D11SwapChain::buildOrResize()
|
|||||||
m_depthStencil->sampleCount(), m_sampleCount);
|
m_depthStencil->sampleCount(), m_sampleCount);
|
||||||
}
|
}
|
||||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
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.",
|
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
m_depthStencil->setPixelSize(pixelSize);
|
||||||
pixelSize.width(), pixelSize.height());
|
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;
|
currentFrameSlot = 0;
|
||||||
|
@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
void release() override;
|
void release() override;
|
||||||
bool build() override;
|
bool build() override;
|
||||||
|
|
||||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||||
uint generation = 0;
|
uint generation = 0;
|
||||||
|
|
||||||
// Keep track of the generation number of each referenced QRhi* to be able
|
// Keep track of the generation number of each referenced QRhi* to be able
|
||||||
@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
BoundStorageBufferData sbuf;
|
BoundStorageBufferData sbuf;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
QVector<BoundResourceData> boundResourceData;
|
QVarLengthArray<BoundResourceData, 8> boundResourceData;
|
||||||
|
|
||||||
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
|
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
|
||||||
QRhiBatchedBindings<UINT> vsubufoffsets;
|
QRhiBatchedBindings<UINT> vsubufoffsets;
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QtGui/private/qopenglextensions_p.h>
|
#include <QtGui/private/qopenglextensions_p.h>
|
||||||
|
#include <QtGui/private/qopenglprogrambinarycache_p.h>
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -275,6 +276,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
#define GL_POINT_SPRITE 0x8861
|
#define GL_POINT_SPRITE 0x8861
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a new QRhiGles2InitParams.
|
Constructs a new QRhiGles2InitParams.
|
||||||
|
|
||||||
@ -583,7 +586,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag
|
|||||||
|
|
||||||
int QRhiGles2::ubufAlignment() const
|
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
|
bool QRhiGles2::isYUpInFramebuffer() const
|
||||||
@ -863,7 +868,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
|
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
|
||||||
bool hasDynamicOffsetInSrb = false;
|
bool hasDynamicOffsetInSrb = false;
|
||||||
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
|
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) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
// no BufUniformRead / AccessUniform because no real uniform buffers are used
|
// no BufUniformRead / AccessUniform because no real uniform buffers are used
|
||||||
@ -2181,7 +2186,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||||||
{
|
{
|
||||||
GLbitfield barriers = 0;
|
GLbitfield barriers = 0;
|
||||||
QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]);
|
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
|
// we only care about after-write, not any other accesses, and
|
||||||
// cannot tell if something was written in a shader several passes
|
// cannot tell if something was written in a shader several passes
|
||||||
// ago: now the previously written resource may be used with an
|
// 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
|
// barrier in theory. Hence setting all barrier bits whenever
|
||||||
// something previously written is used for the first time in a
|
// something previously written is used for the first time in a
|
||||||
// subsequent pass.
|
// subsequent pass.
|
||||||
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
|
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
|
||||||
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access);
|
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
|
||||||
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|
||||||
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
|
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
|
||||||
{
|
{
|
||||||
barriers |= GL_ALL_BARRIER_BITS;
|
barriers |= GL_ALL_BARRIER_BITS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
|
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
|
||||||
for (const QRhiPassResourceTracker::Texture &t : *textures) {
|
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
|
||||||
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access);
|
|
||||||
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|
||||||
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
|
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
|
||||||
{
|
{
|
||||||
@ -2301,7 +2304,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
|
|||||||
int texUnit = 0;
|
int texUnit = 0;
|
||||||
|
|
||||||
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
|
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) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
@ -2707,8 +2710,7 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
|
QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
|
||||||
QShaderDescription *desc, int *glslVersionUsed)
|
|
||||||
{
|
{
|
||||||
const QShader bakedShader = shaderStage.shader();
|
const QShader bakedShader = shaderStage.shader();
|
||||||
QVector<int> versionsToTry;
|
QVector<int> versionsToTry;
|
||||||
@ -2727,8 +2729,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
|||||||
QShaderVersion ver(v, QShaderVersion::GlslEs);
|
QShaderVersion ver(v, QShaderVersion::GlslEs);
|
||||||
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
|
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
|
||||||
if (!source.isEmpty()) {
|
if (!source.isEmpty()) {
|
||||||
if (glslVersionUsed)
|
if (glslVersion)
|
||||||
*glslVersionUsed = v;
|
*glslVersion = v;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2757,8 +2759,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
|||||||
for (int v : versionsToTry) {
|
for (int v : versionsToTry) {
|
||||||
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
|
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
|
||||||
if (!source.isEmpty()) {
|
if (!source.isEmpty()) {
|
||||||
if (glslVersionUsed)
|
if (glslVersion)
|
||||||
*glslVersionUsed = v;
|
*glslVersion = v;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2766,8 +2768,15 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
|||||||
if (source.isEmpty()) {
|
if (source.isEmpty()) {
|
||||||
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
|
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
|
||||||
<< ") in baked shader" << bakedShader;
|
<< ") 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;
|
GLuint shader;
|
||||||
auto cacheIt = m_shaderCache.constFind(shaderStage);
|
auto cacheIt = m_shaderCache.constFind(shaderStage);
|
||||||
@ -2804,7 +2813,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
|||||||
|
|
||||||
f->glAttachShader(program, shader);
|
f->glAttachShader(program, shader);
|
||||||
|
|
||||||
*desc = bakedShader.description();
|
|
||||||
return true;
|
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)
|
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
||||||
: QRhiBuffer(rhi, type, usage, size)
|
: QRhiBuffer(rhi, type, usage, size)
|
||||||
{
|
{
|
||||||
@ -3545,17 +3615,29 @@ bool QGles2GraphicsPipeline::build()
|
|||||||
|
|
||||||
program = rhiD->f->glCreateProgram();
|
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 vsDesc;
|
||||||
QShaderDescription fsDesc;
|
QShaderDescription fsDesc;
|
||||||
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
||||||
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
|
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
|
||||||
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
|
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
|
||||||
if (isVertex) {
|
if (isVertex) {
|
||||||
if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
|
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
vsDesc = shaderStage.shader().description();
|
||||||
} else if (isFragment) {
|
} else if (isFragment) {
|
||||||
if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
|
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
fsDesc = shaderStage.shader().description();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3564,9 +3646,12 @@ bool QGles2GraphicsPipeline::build()
|
|||||||
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
|
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rhiD->linkProgram(program))
|
if (needsCompile && !rhiD->linkProgram(program))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (needsCompile)
|
||||||
|
rhiD->trySaveToDiskCache(program, diskCacheKey);
|
||||||
|
|
||||||
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
|
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
|
||||||
rhiD->gatherUniforms(program, ub, &uniforms);
|
rhiD->gatherUniforms(program, ub, &uniforms);
|
||||||
|
|
||||||
@ -3627,11 +3712,24 @@ bool QGles2ComputePipeline::build()
|
|||||||
program = rhiD->f->glCreateProgram();
|
program = rhiD->f->glCreateProgram();
|
||||||
QShaderDescription csDesc;
|
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;
|
return false;
|
||||||
if (!rhiD->linkProgram(program))
|
|
||||||
|
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
|
||||||
|
|
||||||
|
if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
|
||||||
return false;
|
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())
|
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
|
||||||
rhiD->gatherUniforms(program, ub, &uniforms);
|
rhiD->gatherUniforms(program, ub, &uniforms);
|
||||||
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
|
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
|
||||||
@ -3705,6 +3803,13 @@ bool QGles2SwapChain::buildOrResize()
|
|||||||
m_currentPixelSize = surfacePixelSize();
|
m_currentPixelSize = surfacePixelSize();
|
||||||
pixelSize = m_currentPixelSize;
|
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.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
|
||||||
rt.d.pixelSize = pixelSize;
|
rt.d.pixelSize = pixelSize;
|
||||||
rt.d.dpr = float(m_window->devicePixelRatio());
|
rt.d.dpr = float(m_window->devicePixelRatio());
|
||||||
|
@ -692,13 +692,23 @@ public:
|
|||||||
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
|
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
|
||||||
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
|
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
|
||||||
int effectiveSampleCount(int sampleCount) const;
|
int effectiveSampleCount(int sampleCount) const;
|
||||||
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
|
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||||
QShaderDescription *desc, int *glslVersionUsed);
|
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||||
bool linkProgram(GLuint program);
|
bool linkProgram(GLuint program);
|
||||||
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
||||||
QVector<QGles2UniformDescription> *dst);
|
QVector<QGles2UniformDescription> *dst);
|
||||||
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
|
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
|
||||||
QVector<QGles2SamplerDescription> *dst);
|
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;
|
QOpenGLContext *ctx = nullptr;
|
||||||
bool importedContext = false;
|
bool importedContext = false;
|
||||||
|
@ -656,7 +656,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
} res[KNOWN_STAGES];
|
} res[KNOWN_STAGES];
|
||||||
|
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
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
|
// 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) {
|
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]);
|
QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
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)
|
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
||||||
{
|
{
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
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
|
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
|
||||||
float x, y, w, h;
|
float x, y, w, h;
|
||||||
@ -1105,7 +1072,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
|||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
|
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
|
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
@ -2801,21 +2768,21 @@ bool QMetalShaderResourceBindings::build()
|
|||||||
if (!sortedBindings.isEmpty())
|
if (!sortedBindings.isEmpty())
|
||||||
release();
|
release();
|
||||||
|
|
||||||
sortedBindings = m_bindings;
|
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
[](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())
|
if (!sortedBindings.isEmpty())
|
||||||
maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding;
|
maxBinding = sortedBindings.last().data()->binding;
|
||||||
else
|
else
|
||||||
maxBinding = -1;
|
maxBinding = -1;
|
||||||
|
|
||||||
boundResourceData.resize(sortedBindings.count());
|
boundResourceData.resize(sortedBindings.count());
|
||||||
|
|
||||||
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
|
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]);
|
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
@ -3529,20 +3496,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
|
|||||||
|
|
||||||
QSize QMetalSwapChain::surfacePixelSize()
|
QSize QMetalSwapChain::surfacePixelSize()
|
||||||
{
|
{
|
||||||
// may be called before build, must not access other than m_*
|
Q_ASSERT(m_window);
|
||||||
|
return m_window->size() * m_window->devicePixelRatio();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
|
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
|
||||||
@ -3593,8 +3548,9 @@ bool QMetalSwapChain::buildOrResize()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSView *v = (NSView *) window->winId();
|
NSView *view = reinterpret_cast<NSView *>(window->winId());
|
||||||
d->layer = (CAMetalLayer *) [v layer];
|
Q_ASSERT(view);
|
||||||
|
d->layer = static_cast<CAMetalLayer *>(view.layer);
|
||||||
Q_ASSERT(d->layer);
|
Q_ASSERT(d->layer);
|
||||||
|
|
||||||
chooseFormats();
|
chooseFormats();
|
||||||
@ -3623,7 +3579,15 @@ bool QMetalSwapChain::buildOrResize()
|
|||||||
d->layer.opaque = YES;
|
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;
|
pixelSize = m_currentPixelSize;
|
||||||
|
|
||||||
[d->layer setDevice: rhiD->d->dev];
|
[d->layer setDevice: rhiD->d->dev];
|
||||||
@ -3644,9 +3608,16 @@ bool QMetalSwapChain::buildOrResize()
|
|||||||
m_depthStencil->sampleCount(), m_sampleCount);
|
m_depthStencil->sampleCount(), m_sampleCount);
|
||||||
}
|
}
|
||||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
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.",
|
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
m_depthStencil->setPixelSize(pixelSize);
|
||||||
pixelSize.width(), pixelSize.height());
|
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;
|
rtWrapper.d->pixelSize = pixelSize;
|
||||||
|
@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
void release() override;
|
void release() override;
|
||||||
bool build() override;
|
bool build() override;
|
||||||
|
|
||||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||||
int maxBinding = -1;
|
int maxBinding = -1;
|
||||||
|
|
||||||
struct BoundUniformBufferData {
|
struct BoundUniformBufferData {
|
||||||
@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
BoundStorageBufferData sbuf;
|
BoundStorageBufferData sbuf;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
QVector<BoundResourceData> boundResourceData;
|
QVarLengthArray<BoundResourceData, 8> boundResourceData;
|
||||||
|
|
||||||
uint generation = 0;
|
uint generation = 0;
|
||||||
friend class QRhiMetal;
|
friend class QRhiMetal;
|
||||||
|
@ -2313,7 +2313,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
|
|||||||
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
|
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
|
||||||
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
|
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
|
||||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
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]);
|
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
|
||||||
|
|
||||||
VkWriteDescriptorSet writeInfo;
|
VkWriteDescriptorSet writeInfo;
|
||||||
@ -3556,12 +3556,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
|
|||||||
if (tracker.isEmpty())
|
if (tracker.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
|
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
|
||||||
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
|
QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
|
||||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf);
|
VkAccessFlags access = toVkAccess(it->access);
|
||||||
VkAccessFlags access = toVkAccess(b.access);
|
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
|
||||||
VkPipelineStageFlags stage = toVkPipelineStage(b.stage);
|
QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin);
|
||||||
QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin);
|
|
||||||
if (!s.stage)
|
if (!s.stage)
|
||||||
continue;
|
continue;
|
||||||
if (s.access == access && s.stage == stage) {
|
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.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
bufMemBarrier.srcAccessMask = s.access;
|
bufMemBarrier.srcAccessMask = s.access;
|
||||||
bufMemBarrier.dstAccessMask = access;
|
bufMemBarrier.dstAccessMask = access;
|
||||||
bufMemBarrier.buffer = bufD->buffers[b.slot];
|
bufMemBarrier.buffer = bufD->buffers[it->slot];
|
||||||
bufMemBarrier.size = VK_WHOLE_SIZE;
|
bufMemBarrier.size = VK_WHOLE_SIZE;
|
||||||
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
|
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
@ -3583,13 +3582,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
|
|||||||
0, nullptr);
|
0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
|
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
|
||||||
for (const QRhiPassResourceTracker::Texture &t : *textures) {
|
QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
|
||||||
QVkTexture *texD = QRHI_RES(QVkTexture, t.tex);
|
VkImageLayout layout = toVkLayout(it->access);
|
||||||
VkImageLayout layout = toVkLayout(t.access);
|
VkAccessFlags access = toVkAccess(it->access);
|
||||||
VkAccessFlags access = toVkAccess(t.access);
|
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
|
||||||
VkPipelineStageFlags stage = toVkPipelineStage(t.stage);
|
QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin);
|
||||||
QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin);
|
|
||||||
if (s.access == access && s.stage == stage && s.layout == layout) {
|
if (s.access == access && s.stage == stage && s.layout == layout) {
|
||||||
if (!accessIsWrite(access))
|
if (!accessIsWrite(access))
|
||||||
continue;
|
continue;
|
||||||
@ -3870,7 +3868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
|||||||
bool hasDynamicOffsetInSrb = false;
|
bool hasDynamicOffsetInSrb = false;
|
||||||
|
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
|
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.
|
// 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.
|
// 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) {
|
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]);
|
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
|
||||||
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
|
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
@ -4022,7 +4020,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
|||||||
// and neither srb nor dynamicOffsets has any such ordering
|
// and neither srb nor dynamicOffsets has any such ordering
|
||||||
// requirement.
|
// requirement.
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
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) {
|
if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
for (int i = 0; i < dynamicOffsetCount; ++i) {
|
for (int i = 0; i < dynamicOffsetCount; ++i) {
|
||||||
@ -4750,7 +4748,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic
|
|||||||
dst->compareOp = toVkCompareOp(src.compareOp);
|
dst->compareOp = toVkCompareOp(src.compareOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b)
|
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
|
||||||
{
|
{
|
||||||
switch (b->type) {
|
switch (b->type) {
|
||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
@ -5697,16 +5695,17 @@ bool QVkShaderResourceBindings::build()
|
|||||||
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
||||||
descSets[i] = VK_NULL_HANDLE;
|
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(),
|
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
[](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;
|
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
|
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
|
||||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||||
VkDescriptorSetLayoutBinding vkbinding;
|
VkDescriptorSetLayoutBinding vkbinding;
|
||||||
memset(&vkbinding, 0, sizeof(vkbinding));
|
memset(&vkbinding, 0, sizeof(vkbinding));
|
||||||
vkbinding.binding = uint32_t(b->binding);
|
vkbinding.binding = uint32_t(b->binding);
|
||||||
@ -6315,9 +6314,16 @@ bool QVkSwapChain::buildOrResize()
|
|||||||
m_depthStencil->sampleCount(), m_sampleCount);
|
m_depthStencil->sampleCount(), m_sampleCount);
|
||||||
}
|
}
|
||||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
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.",
|
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
m_depthStencil->setPixelSize(pixelSize);
|
||||||
pixelSize.width(), pixelSize.height());
|
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)
|
if (!m_renderPassDesc)
|
||||||
|
@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
void release() override;
|
void release() override;
|
||||||
bool build() override;
|
bool build() override;
|
||||||
|
|
||||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||||
int poolIndex = -1;
|
int poolIndex = -1;
|
||||||
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
||||||
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
|
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
|
||||||
@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
BoundStorageBufferData sbuf;
|
BoundStorageBufferData sbuf;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
||||||
|
|
||||||
friend class QRhiVulkan;
|
friend class QRhiVulkan;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtGui module of the Qt Toolkit.
|
** 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)
|
bool QFont::fromString(const QString &descrip)
|
||||||
{
|
{
|
||||||
const auto l = descrip.splitRef(QLatin1Char(','));
|
const QStringRef sr = QStringRef(&descrip).trimmed();
|
||||||
|
const auto l = sr.split(QLatin1Char(','));
|
||||||
int count = l.count();
|
const int count = l.count();
|
||||||
if (!count || (count > 2 && count < 9) || count > 11) {
|
if (!count || (count > 2 && count < 9) || count > 11 ||
|
||||||
|
l.first().isEmpty()) {
|
||||||
qWarning("QFont::fromString: Invalid description '%s'",
|
qWarning("QFont::fromString: Invalid description '%s'",
|
||||||
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
|
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
|
||||||
return false;
|
return false;
|
||||||
|
@ -467,6 +467,14 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
|||||||
if (fallbackList.isEmpty())
|
if (fallbackList.isEmpty())
|
||||||
return fallbackList;
|
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)
|
#if defined(Q_OS_MACOS)
|
||||||
// Since we are only returning a list of default fonts for the current language, we do not
|
// 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
|
// 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"));
|
fallbackList.append(QStringLiteral("Apple Symbols"));
|
||||||
#endif
|
#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 &);
|
extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &);
|
||||||
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);
|
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);
|
||||||
|
|
||||||
|
@ -465,7 +465,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
|
|||||||
return QStringList(QLatin1String("android"));
|
return QStringList(QLatin1String("android"));
|
||||||
}
|
}
|
||||||
return QStringList(QLatin1String("fusion"));
|
return QStringList(QLatin1String("fusion"));
|
||||||
|
case DialogButtonBoxLayout:
|
||||||
|
return QVariant(QPlatformDialogHelper::AndroidLayout);
|
||||||
case MouseDoubleClickDistance:
|
case MouseDoubleClickDistance:
|
||||||
{
|
{
|
||||||
int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
|
int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
|
||||||
@ -489,8 +490,6 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
|
|||||||
|
|
||||||
Q_FALLTHROUGH();
|
Q_FALLTHROUGH();
|
||||||
}
|
}
|
||||||
case DialogButtonBoxLayout:
|
|
||||||
return QVariant(QPlatformDialogHelper::AndroidLayout);
|
|
||||||
default:
|
default:
|
||||||
return QPlatformTheme::themeHint(hint);
|
return QPlatformTheme::themeHint(hint);
|
||||||
}
|
}
|
||||||
|
@ -881,7 +881,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial = serialNumber.load();
|
int serial = serialNumber.loadRelaxed();
|
||||||
if (!threadData->canWait || (serial != lastSerial)) {
|
if (!threadData->canWait || (serial != lastSerial)) {
|
||||||
lastSerial = serial;
|
lastSerial = serial;
|
||||||
QCoreApplication::sendPostedEvents();
|
QCoreApplication::sendPostedEvents();
|
||||||
|
@ -43,9 +43,7 @@
|
|||||||
|
|
||||||
- (void)initDrawing
|
- (void)initDrawing
|
||||||
{
|
{
|
||||||
self.wantsLayer = [self layerExplicitlyRequested]
|
[self updateLayerBacking];
|
||||||
|| [self shouldUseMetalLayer]
|
|
||||||
|| [self layerEnabledByMacOS];
|
|
||||||
|
|
||||||
// Enable high-DPI OpenGL for retina displays. Enabling has the side
|
// Enable high-DPI OpenGL for retina displays. Enabling has the side
|
||||||
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
||||||
@ -71,22 +69,13 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)dirtyRect
|
// ----------------------- Layer setup -----------------------
|
||||||
|
|
||||||
|
- (void)updateLayerBacking
|
||||||
{
|
{
|
||||||
Q_UNUSED(dirtyRect);
|
self.wantsLayer = [self layerEnabledByMacOS]
|
||||||
|
|| [self layerExplicitlyRequested]
|
||||||
if (!m_platformWindow)
|
|| [self shouldUseMetalLayer];
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)layerEnabledByMacOS
|
- (BOOL)layerEnabledByMacOS
|
||||||
@ -123,40 +112,81 @@
|
|||||||
return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
|
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
|
- (CALayer *)makeBackingLayer
|
||||||
{
|
{
|
||||||
if ([self shouldUseMetalLayer]) {
|
if ([self shouldUseMetalLayer]) {
|
||||||
// Check if Metal is supported. If it isn't then it's most likely
|
// 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,
|
// too late at this point and the QWindow will be non-functional,
|
||||||
// but we can at least print a warning.
|
// but we can at least print a warning.
|
||||||
if (![MTLCreateSystemDefaultDevice() autorelease]) {
|
if ([MTLCreateSystemDefaultDevice() autorelease]) {
|
||||||
qWarning() << "QWindow initialization error: Metal is not supported";
|
return [CAMetalLayer layer];
|
||||||
return [super makeBackingLayer];
|
} 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];
|
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
|
- (void)setLayer:(CALayer *)layer
|
||||||
{
|
{
|
||||||
qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer
|
qCDebug(lcQpaDrawing) << "Making" << self
|
||||||
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
|
<< (self.wantsLayer ? "layer-backed" : "layer-hosted")
|
||||||
|
<< "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
|
||||||
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
|
: [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];
|
[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
|
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
|
||||||
{
|
{
|
||||||
// We need to set this explicitly since the super implementation
|
// We need to set this explicitly since the super implementation
|
||||||
@ -164,17 +194,95 @@
|
|||||||
return NSViewLayerContentsRedrawDuringViewResize;
|
return NSViewLayerContentsRedrawDuringViewResize;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // Disabled until we enable lazy backingstore resizing
|
|
||||||
- (NSViewLayerContentsPlacement)layerContentsPlacement
|
- (NSViewLayerContentsPlacement)layerContentsPlacement
|
||||||
{
|
{
|
||||||
// Always place the layer at top left without any automatic scaling,
|
// Always place the layer at top left without any automatic scaling.
|
||||||
// so that we can re-use larger layers when resizing a window down.
|
// 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;
|
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
|
- (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) {
|
if (!NSThread.isMainThread) {
|
||||||
// Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
|
// 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
|
// which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
|
||||||
@ -184,29 +292,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(layer == self.layer);
|
|
||||||
|
|
||||||
if (!m_platformWindow)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
|
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());
|
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
|
@end
|
||||||
|
@ -891,13 +891,6 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
|
|||||||
result.profile = QSurfaceFormat::CoreProfile;
|
result.profile = QSurfaceFormat::CoreProfile;
|
||||||
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||||
result.profile = QSurfaceFormat::CompatibilityProfile;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,6 +968,7 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
|
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
|
||||||
|
#define ROBUSTNESS_EXTENSION "GL_ARB_robustness"
|
||||||
|
|
||||||
QOpenGLStaticContext::QOpenGLStaticContext() :
|
QOpenGLStaticContext::QOpenGLStaticContext() :
|
||||||
vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
|
vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
|
||||||
@ -995,9 +989,31 @@ QOpenGLStaticContext::QOpenGLStaticContext() :
|
|||||||
wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
|
wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
|
||||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
|
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
|
||||||
{
|
{
|
||||||
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|
if (defaultFormat.version < 0x0300) {
|
||||||
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
|
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|
||||||
extensions |= SampleBuffers;
|
|| 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)
|
QByteArray QOpenGLStaticContext::getGlString(unsigned int which)
|
||||||
@ -1236,27 +1252,11 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
|
|||||||
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
|
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
|
||||||
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
|
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
|
||||||
|
|
||||||
bool hasRobustness = false;
|
if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) {
|
||||||
if (m_obtainedFormat.majorVersion() < 3) {
|
GLint value = 0;
|
||||||
const char *exts = reinterpret_cast<const char *>(QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS));
|
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
|
||||||
hasRobustness = exts && strstr(exts, "GL_ARB_robustness");
|
if (value == LOSE_CONTEXT_ON_RESET_ARB)
|
||||||
} else {
|
m_obtainedFormat.setOption(QSurfaceFormat::ResetNotification);
|
||||||
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) {
|
|
||||||
m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
|
m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
|
||||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
|
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,8 @@ public:
|
|||||||
enum Extensions
|
enum Extensions
|
||||||
{
|
{
|
||||||
SampleBuffers = 0x1,
|
SampleBuffers = 0x1,
|
||||||
sRGBCapableFramebuffer = 0x2
|
sRGBCapableFramebuffer = 0x2,
|
||||||
|
Robustness = 0x4,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef bool
|
typedef bool
|
||||||
|
@ -2697,10 +2697,16 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (localPos.y() < 0) {
|
if (localPos.y() < 0) {
|
||||||
const int topResizeBarPos = -frameMargins().top();
|
// We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar,
|
||||||
if (localPos.y() >= topResizeBarPos)
|
// 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.
|
*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())) {
|
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
|
||||||
|
@ -79,7 +79,7 @@ QSqlDatabase db = QSqlDatabase::addDatabase("MYDRIVER");
|
|||||||
//! [3]
|
//! [3]
|
||||||
...
|
...
|
||||||
db = QSqlDatabase::addDatabase("QODBC");
|
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()) {
|
if (db.open()) {
|
||||||
// success!
|
// success!
|
||||||
}
|
}
|
||||||
|
@ -2805,8 +2805,11 @@ template <> Q_TESTLIB_EXPORT char *QTest::toString<char>(const char &t)
|
|||||||
*/
|
*/
|
||||||
char *QTest::toString(const char *str)
|
char *QTest::toString(const char *str)
|
||||||
{
|
{
|
||||||
if (!str)
|
if (!str) {
|
||||||
return nullptr;
|
char *msg = new char[1];
|
||||||
|
*msg = '\0';
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
char *msg = new char[strlen(str) + 1];
|
char *msg = new char[strlen(str) + 1];
|
||||||
return qstrcpy(msg, str);
|
return qstrcpy(msg, str);
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,14 @@
|
|||||||
#if QT_CONFIG(lineedit)
|
#if QT_CONFIG(lineedit)
|
||||||
#include "qlineedit.h"
|
#include "qlineedit.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include <qpointer.h>
|
||||||
#include "qpainter.h"
|
#include "qpainter.h"
|
||||||
#include "qwindow.h"
|
#include "qwindow.h"
|
||||||
#include "qpushbutton.h"
|
#include "qpushbutton.h"
|
||||||
#include "qset.h"
|
#include "qset.h"
|
||||||
|
#if QT_CONFIG(shortcut)
|
||||||
|
# include "qshortcut.h"
|
||||||
|
#endif
|
||||||
#include "qstyle.h"
|
#include "qstyle.h"
|
||||||
#include "qvarlengtharray.h"
|
#include "qvarlengtharray.h"
|
||||||
#if defined(Q_OS_MACX)
|
#if defined(Q_OS_MACX)
|
||||||
@ -232,31 +236,24 @@ void QWizardField::findProperty(const QWizardDefaultProperty *properties, int pr
|
|||||||
class QWizardLayoutInfo
|
class QWizardLayoutInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline QWizardLayoutInfo()
|
int topLevelMarginLeft = -1;
|
||||||
: topLevelMarginLeft(-1), topLevelMarginRight(-1), topLevelMarginTop(-1),
|
int topLevelMarginRight = -1;
|
||||||
topLevelMarginBottom(-1), childMarginLeft(-1), childMarginRight(-1),
|
int topLevelMarginTop = -1;
|
||||||
childMarginTop(-1), childMarginBottom(-1), hspacing(-1), vspacing(-1),
|
int topLevelMarginBottom = -1;
|
||||||
wizStyle(QWizard::ClassicStyle), header(false), watermark(false), title(false),
|
int childMarginLeft = -1;
|
||||||
subTitle(false), extension(false), sideWidget(false) {}
|
int childMarginRight = -1;
|
||||||
|
int childMarginTop = -1;
|
||||||
int topLevelMarginLeft;
|
int childMarginBottom = -1;
|
||||||
int topLevelMarginRight;
|
int hspacing = -1;
|
||||||
int topLevelMarginTop;
|
int vspacing = -1;
|
||||||
int topLevelMarginBottom;
|
int buttonSpacing = -1;
|
||||||
int childMarginLeft;
|
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
|
||||||
int childMarginRight;
|
bool header = false;
|
||||||
int childMarginTop;
|
bool watermark = false;
|
||||||
int childMarginBottom;
|
bool title = false;
|
||||||
int hspacing;
|
bool subTitle = false;
|
||||||
int vspacing;
|
bool extension = false;
|
||||||
int buttonSpacing;
|
bool sideWidget = false;
|
||||||
QWizard::WizardStyle wizStyle;
|
|
||||||
bool header;
|
|
||||||
bool watermark;
|
|
||||||
bool title;
|
|
||||||
bool subTitle;
|
|
||||||
bool extension;
|
|
||||||
bool sideWidget;
|
|
||||||
|
|
||||||
bool operator==(const QWizardLayoutInfo &other);
|
bool operator==(const QWizardLayoutInfo &other);
|
||||||
inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
|
inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
|
||||||
@ -486,21 +483,18 @@ class QWizardPagePrivate : public QWidgetPrivate
|
|||||||
public:
|
public:
|
||||||
enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
|
enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
|
||||||
|
|
||||||
inline QWizardPagePrivate()
|
|
||||||
: wizard(0), completeState(Tri_Unknown), explicitlyFinal(false), commit(false) {}
|
|
||||||
|
|
||||||
bool cachedIsComplete() const;
|
bool cachedIsComplete() const;
|
||||||
void _q_maybeEmitCompleteChanged();
|
void _q_maybeEmitCompleteChanged();
|
||||||
void _q_updateCachedCompleteState();
|
void _q_updateCachedCompleteState();
|
||||||
|
|
||||||
QWizard *wizard;
|
QWizard *wizard = nullptr;
|
||||||
QString title;
|
QString title;
|
||||||
QString subTitle;
|
QString subTitle;
|
||||||
QPixmap pixmaps[QWizard::NPixmaps];
|
QPixmap pixmaps[QWizard::NPixmaps];
|
||||||
QVector<QWizardField> pendingFields;
|
QVector<QWizardField> pendingFields;
|
||||||
mutable TriState completeState;
|
mutable TriState completeState = Tri_Unknown;
|
||||||
bool explicitlyFinal;
|
bool explicitlyFinal = false;
|
||||||
bool commit;
|
bool commit = false;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
QMap<int, QString> buttonCustomTexts;
|
QMap<int, QString> buttonCustomTexts;
|
||||||
};
|
};
|
||||||
@ -556,42 +550,6 @@ public:
|
|||||||
Forward
|
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 init();
|
||||||
void reset();
|
void reset();
|
||||||
void cleanupPagesNotInHistory();
|
void cleanupPagesNotInHistory();
|
||||||
@ -631,21 +589,21 @@ public:
|
|||||||
QMap<QString, int> fieldIndexMap;
|
QMap<QString, int> fieldIndexMap;
|
||||||
QVector<QWizardDefaultProperty> defaultPropertyTable;
|
QVector<QWizardDefaultProperty> defaultPropertyTable;
|
||||||
QList<int> history;
|
QList<int> history;
|
||||||
int start;
|
int start = -1;
|
||||||
bool startSetByUser;
|
bool startSetByUser = false;
|
||||||
int current;
|
int current = -1;
|
||||||
bool canContinue;
|
bool canContinue = false;
|
||||||
bool canFinish;
|
bool canFinish = false;
|
||||||
QWizardLayoutInfo layoutInfo;
|
QWizardLayoutInfo layoutInfo;
|
||||||
int disableUpdatesCount;
|
int disableUpdatesCount = 0;
|
||||||
|
|
||||||
QWizard::WizardStyle wizStyle;
|
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
|
||||||
QWizard::WizardOptions opts;
|
QWizard::WizardOptions opts;
|
||||||
QMap<int, QString> buttonCustomTexts;
|
QMap<int, QString> buttonCustomTexts;
|
||||||
bool buttonsHaveCustomLayout;
|
bool buttonsHaveCustomLayout = false;
|
||||||
QList<QWizard::WizardButton> buttonsCustomLayout;
|
QList<QWizard::WizardButton> buttonsCustomLayout;
|
||||||
Qt::TextFormat titleFmt;
|
Qt::TextFormat titleFmt = Qt::AutoText;
|
||||||
Qt::TextFormat subTitleFmt;
|
Qt::TextFormat subTitleFmt = Qt::AutoText;
|
||||||
mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
|
mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
|
||||||
|
|
||||||
union {
|
union {
|
||||||
@ -660,32 +618,35 @@ public:
|
|||||||
} btn;
|
} btn;
|
||||||
mutable QAbstractButton *btns[QWizard::NButtons];
|
mutable QAbstractButton *btns[QWizard::NButtons];
|
||||||
};
|
};
|
||||||
QWizardAntiFlickerWidget *antiFlickerWidget;
|
QWizardAntiFlickerWidget *antiFlickerWidget = nullptr;
|
||||||
QWidget *placeholderWidget1;
|
QWidget *placeholderWidget1 = nullptr;
|
||||||
QWidget *placeholderWidget2;
|
QWidget *placeholderWidget2 = nullptr;
|
||||||
QWizardHeader *headerWidget;
|
QWizardHeader *headerWidget = nullptr;
|
||||||
QWatermarkLabel *watermarkLabel;
|
QWatermarkLabel *watermarkLabel = nullptr;
|
||||||
QWidget *sideWidget;
|
QWidget *sideWidget = nullptr;
|
||||||
QFrame *pageFrame;
|
QFrame *pageFrame = nullptr;
|
||||||
QLabel *titleLabel;
|
QLabel *titleLabel = nullptr;
|
||||||
QLabel *subTitleLabel;
|
QLabel *subTitleLabel = nullptr;
|
||||||
QWizardRuler *bottomRuler;
|
QWizardRuler *bottomRuler = nullptr;
|
||||||
|
|
||||||
QVBoxLayout *pageVBoxLayout;
|
QVBoxLayout *pageVBoxLayout = nullptr;
|
||||||
QHBoxLayout *buttonLayout;
|
QHBoxLayout *buttonLayout = nullptr;
|
||||||
QGridLayout *mainLayout;
|
QGridLayout *mainLayout = nullptr;
|
||||||
|
|
||||||
#if QT_CONFIG(style_windowsvista)
|
#if QT_CONFIG(style_windowsvista)
|
||||||
QVistaHelper *vistaHelper;
|
QVistaHelper *vistaHelper = nullptr;
|
||||||
bool vistaInitPending;
|
# if QT_CONFIG(shortcut)
|
||||||
QVistaHelper::VistaState vistaState;
|
QPointer<QShortcut> vistaNextShortcut;
|
||||||
bool vistaStateChanged;
|
# endif
|
||||||
bool inHandleAeroStyleChange;
|
bool vistaInitPending = true;
|
||||||
|
QVistaHelper::VistaState vistaState = QVistaHelper::Dirty;
|
||||||
|
bool vistaStateChanged = false;
|
||||||
|
bool inHandleAeroStyleChange = false;
|
||||||
#endif
|
#endif
|
||||||
int minimumWidth;
|
int minimumWidth = 0;
|
||||||
int minimumHeight;
|
int minimumHeight = 0;
|
||||||
int maximumWidth;
|
int maximumWidth = QWIDGETSIZE_MAX;
|
||||||
int maximumHeight;
|
int maximumHeight = QWIDGETSIZE_MAX;
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
|
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
|
||||||
@ -720,6 +681,8 @@ void QWizardPrivate::init()
|
|||||||
{
|
{
|
||||||
Q_Q(QWizard);
|
Q_Q(QWizard);
|
||||||
|
|
||||||
|
std::fill(btns, btns + QWizard::NButtons, nullptr);
|
||||||
|
|
||||||
antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
|
antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
|
||||||
wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
|
wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
|
||||||
if (wizStyle == QWizard::MacStyle) {
|
if (wizStyle == QWizard::MacStyle) {
|
||||||
@ -1461,10 +1424,17 @@ void QWizardPrivate::updateButtonTexts()
|
|||||||
// Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
|
// 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.
|
// even in RTL mode, so do the same, even if it might be counter-intuitive.
|
||||||
// The shortcut for 'back' is set in class QVistaBackButton.
|
// The shortcut for 'back' is set in class QVistaBackButton.
|
||||||
#if QT_CONFIG(shortcut)
|
#if QT_CONFIG(shortcut) && QT_CONFIG(style_windowsvista)
|
||||||
if (btns[QWizard::NextButton] && isVistaThemeEnabled())
|
if (btns[QWizard::NextButton] && isVistaThemeEnabled()) {
|
||||||
btns[QWizard::NextButton]->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Right));
|
if (vistaNextShortcut.isNull()) {
|
||||||
#endif
|
vistaNextShortcut =
|
||||||
|
new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right),
|
||||||
|
btns[QWizard::NextButton], SLOT(animateClick()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete vistaNextShortcut;
|
||||||
|
}
|
||||||
|
#endif // shortcut && style_windowsvista
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWizardPrivate::updateButtonLayout()
|
void QWizardPrivate::updateButtonLayout()
|
||||||
|
@ -6204,7 +6204,7 @@ void QWidget::setFocusProxy(QWidget * w)
|
|||||||
|
|
||||||
if (changingAppFocusWidget) {
|
if (changingAppFocusWidget) {
|
||||||
QWidget *newDeepestFocusProxy = d_func()->deepestFocusProxy();
|
QWidget *newDeepestFocusProxy = d_func()->deepestFocusProxy();
|
||||||
QApplicationPrivate::focus_widget = newDeepestFocusProxy ? newDeepestFocusProxy : this;
|
QApplicationPrivate::setFocusWidget(newDeepestFocusProxy ? newDeepestFocusProxy : this, Qt::NoFocusReason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5967,6 +5967,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
|
|||||||
case SP_ArrowLeft:
|
case SP_ArrowLeft:
|
||||||
icon = QIcon::fromTheme(QLatin1String("go-previous"));
|
icon = QIcon::fromTheme(QLatin1String("go-previous"));
|
||||||
break;
|
break;
|
||||||
|
case SP_DialogNoButton:
|
||||||
case SP_DialogCancelButton:
|
case SP_DialogCancelButton:
|
||||||
icon = QIcon::fromTheme(QLatin1String("dialog-cancel"),
|
icon = QIcon::fromTheme(QLatin1String("dialog-cancel"),
|
||||||
QIcon::fromTheme(QLatin1String("process-stop")));
|
QIcon::fromTheme(QLatin1String("process-stop")));
|
||||||
|
@ -44,6 +44,9 @@ private slots:
|
|||||||
void fuzzyCompare();
|
void fuzzyCompare();
|
||||||
void rawNaN_data();
|
void rawNaN_data();
|
||||||
void rawNaN();
|
void rawNaN();
|
||||||
|
#if QT_CONFIG(signaling_nan)
|
||||||
|
void distinctNaN();
|
||||||
|
#endif
|
||||||
void generalNaN_data();
|
void generalNaN_data();
|
||||||
void generalNaN();
|
void generalNaN();
|
||||||
void infinity();
|
void infinity();
|
||||||
@ -139,6 +142,9 @@ void tst_QNumeric::rawNaN_data()
|
|||||||
QTest::addColumn<double>("nan");
|
QTest::addColumn<double>("nan");
|
||||||
|
|
||||||
QTest::newRow("quiet") << qQNaN();
|
QTest::newRow("quiet") << qQNaN();
|
||||||
|
#if QT_CONFIG(signaling_nan)
|
||||||
|
QTest::newRow("signaling") << qSNaN();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QNumeric::rawNaN()
|
void tst_QNumeric::rawNaN()
|
||||||
@ -147,6 +153,15 @@ void tst_QNumeric::rawNaN()
|
|||||||
checkNaN(nan);
|
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()
|
void tst_QNumeric::generalNaN_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<int>("most");
|
QTest::addColumn<int>("most");
|
||||||
|
@ -320,7 +320,7 @@ void tst_QRandomGenerator::generate32_data()
|
|||||||
QTest::newRow("fixed") << (RandomValue32 & RandomDataMask);
|
QTest::newRow("fixed") << (RandomValue32 & RandomDataMask);
|
||||||
QTest::newRow("global") << 0U;
|
QTest::newRow("global") << 0U;
|
||||||
#ifdef QT_BUILD_INTERNAL
|
#ifdef QT_BUILD_INTERNAL
|
||||||
if (qt_has_hwrng())
|
if (qHasHwrng())
|
||||||
QTest::newRow("hwrng") << uint(UseSystemRNG);
|
QTest::newRow("hwrng") << uint(UseSystemRNG);
|
||||||
QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG);
|
QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG);
|
||||||
# ifdef HAVE_FALLBACK_ENGINE
|
# ifdef HAVE_FALLBACK_ENGINE
|
||||||
@ -755,7 +755,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data()
|
|||||||
|
|
||||||
auto newRow = [&](quint32 max) {
|
auto newRow = [&](quint32 max) {
|
||||||
#ifdef QT_BUILD_INTERNAL
|
#ifdef QT_BUILD_INTERNAL
|
||||||
if (qt_has_hwrng())
|
if (qHasHwrng())
|
||||||
QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max;
|
QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max;
|
||||||
QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max;
|
QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max;
|
||||||
# ifdef HAVE_FALLBACK_ENGINE
|
# ifdef HAVE_FALLBACK_ENGINE
|
||||||
@ -868,7 +868,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data()
|
|||||||
|
|
||||||
auto newRow = [&](double min, double sup) {
|
auto newRow = [&](double min, double sup) {
|
||||||
#ifdef QT_BUILD_INTERNAL
|
#ifdef QT_BUILD_INTERNAL
|
||||||
if (qt_has_hwrng())
|
if (qHasHwrng())
|
||||||
QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup;
|
QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup;
|
||||||
QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup;
|
QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup;
|
||||||
# ifdef HAVE_FALLBACK_ENGINE
|
# ifdef HAVE_FALLBACK_ENGINE
|
||||||
|
@ -1413,10 +1413,12 @@ void tst_QCborValue::toCbor_data()
|
|||||||
// The rest of these tests are conversions whose decoding does not yield
|
// The rest of these tests are conversions whose decoding does not yield
|
||||||
// back the same QCborValue.
|
// back the same QCborValue.
|
||||||
|
|
||||||
|
#if QT_CONFIG(signaling_nan)
|
||||||
// Signalling NaN get normalized to quiet ones
|
// 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("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("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);
|
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
|
// Floating point written as integers are read back as integers
|
||||||
QTest::newRow("UseInteger:0") << QCborValue(0.) << raw("\x00") << QCborValue::EncodingOptions(QCborValue::UseIntegers);
|
QTest::newRow("UseInteger:0") << QCborValue(0.) << raw("\x00") << QCborValue::EncodingOptions(QCborValue::UseIntegers);
|
||||||
|
@ -3468,6 +3468,9 @@ void tst_QDateTime::timeZones() const
|
|||||||
|
|
||||||
void tst_QDateTime::systemTimeZoneChange() 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
|
// Set the timezone to Brisbane time
|
||||||
TimeZoneRollback useZone(QByteArray("AEST-10:00"));
|
TimeZoneRollback useZone(QByteArray("AEST-10:00"));
|
||||||
|
|
||||||
@ -3485,9 +3488,6 @@ void tst_QDateTime::systemTimeZoneChange() const
|
|||||||
useZone.reset(QByteArray("IST-05:30"));
|
useZone.reset(QByteArray("IST-05:30"));
|
||||||
|
|
||||||
QCOMPARE(localDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime));
|
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());
|
QVERIFY(localMsecs != localDate.toMSecsSinceEpoch());
|
||||||
QCOMPARE(utcDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC));
|
QCOMPARE(utcDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC));
|
||||||
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);
|
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
[insert_remove_loop]
|
|
||||||
msvc-2019
|
|
6
tests/auto/gui/kernel/qopenglwindow/BLACKLIST
Normal file
6
tests/auto/gui/kernel/qopenglwindow/BLACKLIST
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[basic]
|
||||||
|
winrt
|
||||||
|
[resize]
|
||||||
|
winrt
|
||||||
|
[painter]
|
||||||
|
winrt
|
@ -4,5 +4,3 @@ TARGET = tst_qopenglwindow
|
|||||||
QT += core-private gui-private testlib
|
QT += core-private gui-private testlib
|
||||||
|
|
||||||
SOURCES += tst_qopenglwindow.cpp
|
SOURCES += tst_qopenglwindow.cpp
|
||||||
|
|
||||||
win32:CONFIG+=insignificant_test # QTBUG-46452, QTBUG-49630
|
|
||||||
|
@ -88,7 +88,9 @@ private slots:
|
|||||||
|
|
||||||
void testToFillPolygons();
|
void testToFillPolygons();
|
||||||
|
|
||||||
|
#if QT_CONFIG(signaling_nan)
|
||||||
void testNaNandInfinites();
|
void testNaNandInfinites();
|
||||||
|
#endif
|
||||||
|
|
||||||
void closing();
|
void closing();
|
||||||
|
|
||||||
@ -1228,6 +1230,7 @@ void tst_QPainterPath::testToFillPolygons()
|
|||||||
QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
|
QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_CONFIG(signaling_nan)
|
||||||
void tst_QPainterPath::testNaNandInfinites()
|
void tst_QPainterPath::testNaNandInfinites()
|
||||||
{
|
{
|
||||||
QPainterPath path1;
|
QPainterPath path1;
|
||||||
@ -1271,6 +1274,7 @@ void tst_QPainterPath::testNaNandInfinites()
|
|||||||
path1.lineTo(QPointF(1, 1));
|
path1.lineTo(QPointF(1, 1));
|
||||||
QVERIFY(path1 != path2);
|
QVERIFY(path1 != path2);
|
||||||
}
|
}
|
||||||
|
#endif // signaling_nan
|
||||||
|
|
||||||
void tst_QPainterPath::connectPathDuplicatePoint()
|
void tst_QPainterPath::connectPathDuplicatePoint()
|
||||||
{
|
{
|
||||||
|
@ -66,6 +66,8 @@ private slots:
|
|||||||
void defaultFamily();
|
void defaultFamily();
|
||||||
void toAndFromString();
|
void toAndFromString();
|
||||||
void fromStringWithoutStyleName();
|
void fromStringWithoutStyleName();
|
||||||
|
void fromDegenerateString_data();
|
||||||
|
void fromDegenerateString();
|
||||||
|
|
||||||
void sharing();
|
void sharing();
|
||||||
void familyNameWithCommaQuote_data();
|
void familyNameWithCommaQuote_data();
|
||||||
@ -604,6 +606,25 @@ void tst_QFont::fromStringWithoutStyleName()
|
|||||||
QCOMPARE(font2.toString(), str);
|
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()
|
void tst_QFont::sharing()
|
||||||
{
|
{
|
||||||
|
@ -2712,13 +2712,8 @@ void tst_QWizard::taskQTBUG_46894_nextButtonShortcut()
|
|||||||
wizard.show();
|
wizard.show();
|
||||||
QVERIFY(QTest::qWaitForWindowExposed(&wizard));
|
QVERIFY(QTest::qWaitForWindowExposed(&wizard));
|
||||||
|
|
||||||
if (wizard.button(QWizard::NextButton)->text() == "&Next") {
|
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
||||||
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
|
||||||
QKeySequence(Qt::ALT | Qt::Key_Right));
|
|
||||||
} else {
|
|
||||||
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
|
||||||
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +379,7 @@ void TiledPixmapPainter::paintEvent(QPaintEvent *event)
|
|||||||
// large pixmap: 2 x 2 tiles
|
// large pixmap: 2 x 2 tiles
|
||||||
// 2x pixmap : 4 x 4 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.
|
// will be drawn in high resolution.
|
||||||
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X);
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X);
|
||||||
yoff += tiles * pixmapEdge + 10;
|
yoff += tiles * pixmapEdge + 10;
|
||||||
|
@ -298,7 +298,7 @@ void Window::init()
|
|||||||
m_sc = m_r->newSwapChain();
|
m_sc = m_r->newSwapChain();
|
||||||
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
||||||
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
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,
|
1,
|
||||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||||
releasePool << m_ds;
|
releasePool << m_ds;
|
||||||
@ -376,16 +376,12 @@ void Window::releaseResources()
|
|||||||
|
|
||||||
void Window::resizeSwapChain()
|
void Window::resizeSwapChain()
|
||||||
{
|
{
|
||||||
const QSize outputSize = m_sc->surfacePixelSize();
|
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
|
||||||
|
|
||||||
m_ds->setPixelSize(outputSize);
|
|
||||||
m_ds->build(); // == m_ds->release(); m_ds->build();
|
|
||||||
|
|
||||||
m_hasSwapChain = m_sc->buildOrResize();
|
|
||||||
|
|
||||||
m_elapsedMs = 0;
|
m_elapsedMs = 0;
|
||||||
m_elapsedCount = 0;
|
m_elapsedCount = 0;
|
||||||
|
|
||||||
|
const QSize outputSize = m_sc->currentPixelSize();
|
||||||
m_proj = m_r->clipSpaceCorrMatrix();
|
m_proj = m_r->clipSpaceCorrMatrix();
|
||||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
||||||
m_proj.translate(0, 0, -4);
|
m_proj.translate(0, 0, -4);
|
||||||
|
@ -200,12 +200,10 @@ void Window::customInit()
|
|||||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
|
||||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
|
|
||||||
for (int i = 0; i < ATTCOUNT; ++i) {
|
QRhiGraphicsPipeline::TargetBlend blends[ATTCOUNT]; // defaults to blending == false
|
||||||
QRhiGraphicsPipeline::TargetBlend blend;
|
d.triPs->setTargetBlends(blends, blends + ATTCOUNT);
|
||||||
blends.append(blend);
|
|
||||||
}
|
|
||||||
d.triPs->setTargetBlends(blends);
|
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
{ 5 * sizeof(float) }
|
{ 5 * sizeof(float) }
|
||||||
});
|
});
|
||||||
|
@ -240,7 +240,7 @@ void Window::customInit()
|
|||||||
#else
|
#else
|
||||||
d.msaaTriPs->setSampleCount(1);
|
d.msaaTriPs->setSampleCount(1);
|
||||||
#endif
|
#endif
|
||||||
d.msaaTriPs->setShaderStages(d.triPs->shaderStages());
|
d.msaaTriPs->setShaderStages(d.triPs->cbeginShaderStages(), d.triPs->cendShaderStages());
|
||||||
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
|
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
|
||||||
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
|
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
|
||||||
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);
|
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);
|
||||||
|
@ -400,7 +400,7 @@ void Window::init()
|
|||||||
{
|
{
|
||||||
m_sc = r.r->newSwapChain();
|
m_sc = r.r->newSwapChain();
|
||||||
m_ds = r.r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
m_ds = r.r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||||
QSize(), // no need to set the size yet
|
QSize(),
|
||||||
1,
|
1,
|
||||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||||
m_releasePool << m_ds;
|
m_releasePool << m_ds;
|
||||||
@ -427,13 +427,9 @@ void Window::releaseResources()
|
|||||||
|
|
||||||
void Window::resizeSwapChain()
|
void Window::resizeSwapChain()
|
||||||
{
|
{
|
||||||
const QSize outputSize = m_sc->surfacePixelSize();
|
|
||||||
|
|
||||||
m_ds->setPixelSize(outputSize);
|
|
||||||
m_ds->build();
|
|
||||||
|
|
||||||
m_hasSwapChain = m_sc->buildOrResize();
|
m_hasSwapChain = m_sc->buildOrResize();
|
||||||
|
|
||||||
|
const QSize outputSize = m_sc->currentPixelSize();
|
||||||
m_proj = r.r->clipSpaceCorrMatrix();
|
m_proj = r.r->clipSpaceCorrMatrix();
|
||||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
||||||
m_proj.translate(0, 0, -4);
|
m_proj.translate(0, 0, -4);
|
||||||
|
@ -441,7 +441,7 @@ void Renderer::init()
|
|||||||
{
|
{
|
||||||
m_sc = r->newSwapChain();
|
m_sc = r->newSwapChain();
|
||||||
m_ds = r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
m_ds = r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||||
QSize(), // no need to set the size yet
|
QSize(),
|
||||||
1,
|
1,
|
||||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||||
m_releasePool << m_ds;
|
m_releasePool << m_ds;
|
||||||
@ -543,11 +543,9 @@ void Renderer::render(bool newlyExposed, bool wakeBeforePresent)
|
|||||||
|
|
||||||
auto buildOrResizeSwapChain = [this] {
|
auto buildOrResizeSwapChain = [this] {
|
||||||
qDebug() << "renderer" << this << "build or resize swapchain for window" << window;
|
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();
|
m_hasSwapChain = m_sc->buildOrResize();
|
||||||
|
const QSize outputSize = m_sc->currentPixelSize();
|
||||||
|
qDebug() << " size is" << outputSize;
|
||||||
m_proj = r->clipSpaceCorrMatrix();
|
m_proj = r->clipSpaceCorrMatrix();
|
||||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
||||||
m_proj.translate(0, 0, -4);
|
m_proj.translate(0, 0, -4);
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#include <QPlatformSurfaceEvent>
|
#include <QPlatformSurfaceEvent>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
#include <QtGui/private/qshader_p.h>
|
#include <QtGui/private/qshader_p.h>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
@ -70,7 +71,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_CONFIG(vulkan)
|
#if QT_CONFIG(vulkan)
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QtGui/private/qrhivulkan_p.h>
|
#include <QtGui/private/qrhivulkan_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -307,7 +307,7 @@ void Window::init()
|
|||||||
m_sc = m_r->newSwapChain();
|
m_sc = m_r->newSwapChain();
|
||||||
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
||||||
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
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,
|
sampleCount,
|
||||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||||
m_sc->setWindow(this);
|
m_sc->setWindow(this);
|
||||||
@ -344,16 +344,12 @@ void Window::releaseResources()
|
|||||||
|
|
||||||
void Window::resizeSwapChain()
|
void Window::resizeSwapChain()
|
||||||
{
|
{
|
||||||
const QSize outputSize = m_sc->surfacePixelSize();
|
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
|
||||||
|
|
||||||
m_ds->setPixelSize(outputSize);
|
|
||||||
m_ds->build(); // == m_ds->release(); m_ds->build();
|
|
||||||
|
|
||||||
m_hasSwapChain = m_sc->buildOrResize();
|
|
||||||
|
|
||||||
m_frameCount = 0;
|
m_frameCount = 0;
|
||||||
m_timer.restart();
|
m_timer.restart();
|
||||||
|
|
||||||
|
const QSize outputSize = m_sc->currentPixelSize();
|
||||||
m_proj = m_r->clipSpaceCorrMatrix();
|
m_proj = m_r->clipSpaceCorrMatrix();
|
||||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
||||||
m_proj.translate(0, 0, -4);
|
m_proj.translate(0, 0, -4);
|
||||||
@ -444,6 +440,8 @@ int main(int argc, char **argv)
|
|||||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
QLoggingCategory::setFilterRules(QLatin1String("qt.rhi.*=true"));
|
||||||
|
|
||||||
// Defaults.
|
// Defaults.
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
graphicsApi = D3D11;
|
graphicsApi = D3D11;
|
||||||
|
@ -68,6 +68,8 @@ struct {
|
|||||||
QRhiTexture *newTex = nullptr;
|
QRhiTexture *newTex = nullptr;
|
||||||
QRhiTexture *importedTex = nullptr;
|
QRhiTexture *importedTex = nullptr;
|
||||||
int testStage = 0;
|
int testStage = 0;
|
||||||
|
|
||||||
|
QRhiShaderResourceBinding bindings[2];
|
||||||
} d;
|
} d;
|
||||||
|
|
||||||
void Window::customInit()
|
void Window::customInit()
|
||||||
@ -100,10 +102,10 @@ void Window::customInit()
|
|||||||
|
|
||||||
d.srb = m_r->newShaderResourceBindings();
|
d.srb = m_r->newShaderResourceBindings();
|
||||||
d.releasePool << d.srb;
|
d.releasePool << d.srb;
|
||||||
d.srb->setBindings({
|
|
||||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
d.bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf);
|
||||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
|
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler);
|
||||||
});
|
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||||
d.srb->build();
|
d.srb->build();
|
||||||
|
|
||||||
d.ps = m_r->newGraphicsPipeline();
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
@ -211,9 +213,8 @@ void Window::customRender()
|
|||||||
u->copyTexture(d.newTex, d.tex, desc);
|
u->copyTexture(d.newTex, d.tex, desc);
|
||||||
|
|
||||||
// Now replace d.tex with d.newTex as the shader resource.
|
// Now replace d.tex with d.newTex as the shader resource.
|
||||||
auto bindings = d.srb->bindings();
|
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||||
d.srb->setBindings(bindings);
|
|
||||||
// "rebuild", whatever that means for a given backend. This srb is
|
// "rebuild", whatever that means for a given backend. This srb is
|
||||||
// already live as the ps in the setGraphicsPipeline references it,
|
// already live as the ps in the setGraphicsPipeline references it,
|
||||||
// but that's fine. Changes will be picked up automatically.
|
// but that's fine. Changes will be picked up automatically.
|
||||||
@ -259,9 +260,8 @@ void Window::customRender()
|
|||||||
// underneath (owned by d.tex)
|
// underneath (owned by d.tex)
|
||||||
|
|
||||||
// switch to showing d.importedTex
|
// switch to showing d.importedTex
|
||||||
auto bindings = d.srb->bindings();
|
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
|
||||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
|
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||||
d.srb->setBindings(bindings);
|
|
||||||
d.srb->build();
|
d.srb->build();
|
||||||
} else {
|
} else {
|
||||||
qWarning("Accessing native texture object is not supported");
|
qWarning("Accessing native texture object is not supported");
|
||||||
@ -270,9 +270,8 @@ void Window::customRender()
|
|||||||
|
|
||||||
// Exercise uploading uncompressed data without a QImage.
|
// Exercise uploading uncompressed data without a QImage.
|
||||||
if (d.testStage == 7) {
|
if (d.testStage == 7) {
|
||||||
auto bindings = d.srb->bindings();
|
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||||
d.srb->setBindings(bindings);
|
|
||||||
d.srb->build();
|
d.srb->build();
|
||||||
|
|
||||||
const QSize sz(221, 139);
|
const QSize sz(221, 139);
|
||||||
|
@ -94,11 +94,11 @@ void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp)
|
|||||||
|
|
||||||
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
|
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
|
||||||
premulAlphaBlend.enable = true;
|
premulAlphaBlend.enable = true;
|
||||||
QVector<QRhiGraphicsPipeline::TargetBlend> rtblends;
|
QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> rtblends;
|
||||||
for (int i = 0; i < m_colorAttCount; ++i)
|
for (int i = 0; i < m_colorAttCount; ++i)
|
||||||
rtblends << premulAlphaBlend;
|
rtblends << premulAlphaBlend;
|
||||||
|
|
||||||
m_ps->setTargetBlends(rtblends);
|
m_ps->setTargetBlends(rtblends.cbegin(), rtblends.cend());
|
||||||
m_ps->setSampleCount(m_sampleCount);
|
m_ps->setSampleCount(m_sampleCount);
|
||||||
|
|
||||||
if (m_depthWrite) { // TriangleOnCube may want to exercise this
|
if (m_depthWrite) { // TriangleOnCube may want to exercise this
|
||||||
|
Loading…
x
Reference in New Issue
Block a user