Merge "Merge remote-tracking branch 'origin/5.14' into 5.15"
This commit is contained in:
commit
8791a8398a
@ -484,6 +484,17 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"signaling_nan": {
|
||||
"label": "Signaling NaN for doubles",
|
||||
"type": "compile",
|
||||
"test": {
|
||||
"head": [ "#include <limits>" ],
|
||||
"main": [
|
||||
"using B = std::numeric_limits<double>;",
|
||||
"static_assert(B::has_signaling_NaN, \"System lacks signaling NaN\");"
|
||||
]
|
||||
}
|
||||
},
|
||||
"sse2": {
|
||||
"label": "SSE2 instructions",
|
||||
"type": "x86Simd"
|
||||
@ -1005,6 +1016,11 @@
|
||||
{ "type": "define", "name": "QT_REDUCE_RELOCATIONS" }
|
||||
]
|
||||
},
|
||||
"signaling_nan": {
|
||||
"label": "Signaling NaN",
|
||||
"condition": "tests.signaling_nan",
|
||||
"output": [ "publicFeature" ]
|
||||
},
|
||||
"sse2": {
|
||||
"label": "SSE2",
|
||||
"condition": "(arch.i386 || arch.x86_64) && tests.sse2",
|
||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qt_");
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qt_");
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
||||
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qt_");
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
|
@ -128,7 +128,7 @@ int main(int argc, char *argv[])
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifndef QT_NO_TRANSLATION
|
||||
QString translatorFileName = QLatin1String("qt_");
|
||||
QString translatorFileName = QLatin1String("qtbase_");
|
||||
translatorFileName += QLocale::system().name();
|
||||
QTranslator *translator = new QTranslator(&app);
|
||||
if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
|
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
|
||||
\c lrelease in the executable, under \l{QM_FILES_RESOURCE_PREFIX}.
|
||||
Requires \c lrelease to be set, too. Not set by default.
|
||||
\row \li create_libtool \li Create a libtool .la file for the currently
|
||||
built library.
|
||||
\row \li create_pc \li Create a pkg-config .pc file for the currently built
|
||||
library.
|
||||
\row \li no_batch \li NMake only: Turn off generation of NMake batch rules
|
||||
or inference rules.
|
||||
\row \li skip_target_version_ext \li Suppress the automatic version number
|
||||
appended to the DLL file name on Windows.
|
||||
\row \li suppress_vcproj_warnings \li Suppress warnings of the VS project
|
||||
generator.
|
||||
\row \li windeployqt \li Automatically invoke windeployqt after linking,
|
||||
and add the output as deployment items.
|
||||
\row \li dont_recurse \li Suppress qmake recursion for the current
|
||||
subproject.
|
||||
\row \li no_include_pwd \li Do not add the current directory to
|
||||
INCLUDEPATHS.
|
||||
\endtable
|
||||
|
||||
When you use the \c debug_and_release option (which is the default under
|
||||
@ -1039,6 +1055,8 @@
|
||||
qmake will process all libraries linked to
|
||||
by the application and find their meta-information (see
|
||||
\l{LibDepend}{Library Dependencies} for more info).
|
||||
\row \li no_install_prl \li This option disables the generation of
|
||||
installation rules for generated .prl files.
|
||||
\endtable
|
||||
|
||||
\note The \c create_prl option is required when \e {building} a
|
||||
|
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.",
|
||||
"Homepage": "https://www.sqlite.org/",
|
||||
"Version": "3.28.0",
|
||||
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3280000.zip",
|
||||
"Version": "3.29.0",
|
||||
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3290000.zip",
|
||||
"License": "Public Domain",
|
||||
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
|
||||
}
|
||||
|
7134
src/3rdparty/sqlite/sqlite3.c
vendored
7134
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()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.28.0"
|
||||
#define SQLITE_VERSION_NUMBER 3028000
|
||||
#define SQLITE_SOURCE_ID "2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f83156b50"
|
||||
#define SQLITE_VERSION "3.29.0"
|
||||
#define SQLITE_VERSION_NUMBER 3029000
|
||||
#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -1296,8 +1296,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
|
||||
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
|
||||
** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
|
||||
** to test whether a file is at least readable. The file can be a
|
||||
** directory.
|
||||
** to test whether a file is at least readable. The SQLITE_ACCESS_READ
|
||||
** flag is never actually used and is not implemented in the built-in
|
||||
** VFSes of SQLite. The file is named by the second argument and can be a
|
||||
** directory. The xAccess method returns [SQLITE_OK] on success or some
|
||||
** non-zero error code if there is an I/O error or if the name of
|
||||
** the file given in the second argument is illegal. If SQLITE_OK
|
||||
** is returned, then non-zero or zero is written into *pResOut to indicate
|
||||
** whether or not the file is accessible.
|
||||
**
|
||||
** ^SQLite will always allocate at least mxPathname+1 bytes for the
|
||||
** output buffer xFullPathname. The exact size of the output buffer
|
||||
@ -2198,6 +2204,7 @@ struct sqlite3_mem_methods {
|
||||
** features include but are not limited to the following:
|
||||
** <ul>
|
||||
** <li> The [PRAGMA writable_schema=ON] statement.
|
||||
** <li> The [PRAGMA journal_mode=OFF] statement.
|
||||
** <li> Writes to the [sqlite_dbpage] virtual table.
|
||||
** <li> Direct writes to [shadow tables].
|
||||
** </ul>
|
||||
@ -2213,6 +2220,34 @@ struct sqlite3_mem_methods {
|
||||
** integer into which is written 0 or 1 to indicate whether the writable_schema
|
||||
** is enabled or disabled following this call.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
|
||||
** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
|
||||
** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
|
||||
** the legacy behavior of the [ALTER TABLE RENAME] command such it
|
||||
** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
|
||||
** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
|
||||
** additional information. This feature can also be turned on and off
|
||||
** using the [PRAGMA legacy_alter_table] statement.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_DQS_DML]]
|
||||
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
|
||||
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
|
||||
** the legacy [double-quoted string literal] misfeature for DML statement
|
||||
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
|
||||
** default value of this setting is determined by the [-DSQLITE_DQS]
|
||||
** compile-time option.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_DQS_DDL]]
|
||||
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
|
||||
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
|
||||
** the legacy [double-quoted string literal] misfeature for DDL statements,
|
||||
** such as CREATE TABLE and CREATE INDEX. The
|
||||
** default value of this setting is determined by the [-DSQLITE_DQS]
|
||||
** compile-time option.
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
|
||||
@ -2227,7 +2262,10 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */
|
||||
#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
|
||||
#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */
|
||||
#define SQLITE_DBCONFIG_MAX 1011 /* Largest DBCONFIG */
|
||||
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
|
||||
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
|
||||
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
|
||||
#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extended Result Codes
|
||||
@ -7319,7 +7357,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_SORTER_MMAP 24
|
||||
#define SQLITE_TESTCTRL_IMPOSTER 25
|
||||
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
|
||||
#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
|
||||
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
|
||||
#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
|
@ -416,7 +416,7 @@ public:
|
||||
LoadArchiveMemberHint = 0x04
|
||||
};
|
||||
Q_DECLARE_FLAGS(LoadHints, LoadHint)
|
||||
Q_FLAG(LoadHints)
|
||||
Q_FLAG(LoadHint)
|
||||
...
|
||||
}
|
||||
//! [39]
|
||||
|
@ -109,6 +109,7 @@
|
||||
# define QT_FEATURE_renameat2 -1
|
||||
#endif
|
||||
#define QT_FEATURE_sharedmemory -1
|
||||
#define QT_FEATURE_signaling_nan -1
|
||||
#define QT_FEATURE_slog2 -1
|
||||
#ifdef __GLIBC_PREREQ
|
||||
# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)
|
||||
|
@ -81,11 +81,13 @@ Q_CORE_EXPORT bool qIsNaN(float f) { return qt_is_nan(f); }
|
||||
*/
|
||||
Q_CORE_EXPORT bool qIsFinite(float f) { return qt_is_finite(f); }
|
||||
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
/*!
|
||||
Returns the bit pattern of a signalling NaN as a double.
|
||||
\relates <QtGlobal>
|
||||
*/
|
||||
Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Returns the bit pattern of a quiet NaN as a double.
|
||||
|
@ -44,7 +44,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
|
||||
@ -53,7 +52,9 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
|
||||
#endif
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
|
||||
|
||||
@ -61,7 +62,9 @@ Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
|
||||
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
|
||||
|
||||
#define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
|
||||
#define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
# define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
|
||||
#endif
|
||||
#define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -133,13 +133,14 @@ Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
// Signaling NaN
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
|
||||
{
|
||||
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
|
||||
"platform has no definition for signaling NaN for type double");
|
||||
return std::numeric_limits<double>::signaling_NaN();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Quiet NaN
|
||||
Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept
|
||||
|
@ -90,47 +90,6 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
static qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept;
|
||||
|
||||
# ifdef Q_PROCESSOR_X86_64
|
||||
# define _rdrandXX_step _rdrand64_step
|
||||
# else
|
||||
# define _rdrandXX_step _rdrand32_step
|
||||
# endif
|
||||
|
||||
static QT_FUNCTION_TARGET(RDRND) qsizetype qt_random_cpu(void *buffer, qsizetype count) noexcept
|
||||
{
|
||||
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
|
||||
unsigned *end = ptr + count;
|
||||
int retries = 10;
|
||||
|
||||
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
|
||||
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
|
||||
ptr += sizeof(qregisteruint)/sizeof(*ptr);
|
||||
else if (--retries == 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
|
||||
bool ok = _rdrand32_step(ptr);
|
||||
if (!ok && --retries)
|
||||
continue;
|
||||
if (ok)
|
||||
++ptr;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ptr - reinterpret_cast<unsigned *>(buffer);
|
||||
}
|
||||
#else
|
||||
static qsizetype qt_random_cpu(void *, qsizetype)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// may be "overridden" by a member enum
|
||||
FillBufferNoexcept = true
|
||||
@ -371,8 +330,8 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin,
|
||||
}
|
||||
|
||||
qsizetype filled = 0;
|
||||
if (qt_has_hwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
|
||||
filled += qt_random_cpu(buffer, count);
|
||||
if (qHasHwrng() && (uint(qt_randomdevice_control.loadAcquire()) & SkipHWRNG) == 0)
|
||||
filled += qRandomCpu(buffer, count);
|
||||
|
||||
if (filled != count && (uint(qt_randomdevice_control.loadAcquire()) & SkipSystemRNG) == 0) {
|
||||
qsizetype bytesFilled =
|
||||
|
@ -81,14 +81,6 @@ static const struct {
|
||||
} qt_randomdevice_control;
|
||||
#endif
|
||||
|
||||
inline bool qt_has_hwrng()
|
||||
{
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
return qCpuHasFeature(RDRND);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -249,16 +249,18 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
|
||||
isSymLink(). The symLinkTarget() function provides the name of the file
|
||||
the symlink points to.
|
||||
|
||||
On Unix (including \macos and iOS), the symlink has the same size() has
|
||||
the file it points to, because Unix handles symlinks
|
||||
transparently; similarly, opening a symlink using QFile
|
||||
effectively opens the link's target. For example:
|
||||
On Unix (including \macos and iOS), the property getter functions in this
|
||||
class return the properties such as times and size of the target file, not
|
||||
the symlink, because Unix handles symlinks transparently. Opening a symlink
|
||||
using QFile effectively opens the link's target. For example:
|
||||
|
||||
\snippet code/src_corelib_io_qfileinfo.cpp 0
|
||||
|
||||
On Windows, shortcuts are \c .lnk files. The reported size() is that of
|
||||
the shortcut (not the link's target), and opening a shortcut using QFile
|
||||
opens the \c .lnk file. For example:
|
||||
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
|
||||
on Unix systems, the property getters return the size of the targeted file,
|
||||
not the \c .lnk file itself. This behavior is deprecated and will likely be
|
||||
removed in a future version of Qt, after which \c .lnk files will be treated
|
||||
as regular files.
|
||||
|
||||
\snippet code/src_corelib_io_qfileinfo.cpp 1
|
||||
|
||||
@ -903,6 +905,9 @@ QDir QFileInfo::absoluteDir() const
|
||||
/*!
|
||||
Returns \c true if the user can read the file; otherwise returns \c false.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is
|
||||
readable (not the symlink).
|
||||
|
||||
\note If the \l{NTFS permissions} check has not been enabled, the result
|
||||
on Windows will merely reflect whether the file exists.
|
||||
|
||||
@ -920,6 +925,9 @@ bool QFileInfo::isReadable() const
|
||||
/*!
|
||||
Returns \c true if the user can write to the file; otherwise returns \c false.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is
|
||||
writeable (not the symlink).
|
||||
|
||||
\note If the \l{NTFS permissions} check has not been enabled, the result on
|
||||
Windows will merely reflect whether the file is marked as Read Only.
|
||||
|
||||
@ -937,6 +945,9 @@ bool QFileInfo::isWritable() const
|
||||
/*!
|
||||
Returns \c true if the file is executable; otherwise returns \c false.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is
|
||||
executable (not the symlink).
|
||||
|
||||
\sa isReadable(), isWritable(), permission()
|
||||
*/
|
||||
bool QFileInfo::isExecutable() const
|
||||
@ -951,8 +962,13 @@ bool QFileInfo::isExecutable() const
|
||||
/*!
|
||||
Returns \c true if this is a `hidden' file; otherwise returns \c false.
|
||||
|
||||
\b{Note:} This function returns \c true for the special entries
|
||||
"." and ".." on Unix, even though QDir::entryList threats them as shown.
|
||||
\b{Note:} This function returns \c true for the special entries "." and
|
||||
".." on Unix, even though QDir::entryList threats them as shown. And note
|
||||
that, since this function inspects the file name, on Unix it will inspect
|
||||
the name of the symlink, if this file is a symlink, not the target's name.
|
||||
|
||||
On Windows, this function returns \c true if the target file is hidden (not
|
||||
the symlink).
|
||||
*/
|
||||
bool QFileInfo::isHidden() const
|
||||
{
|
||||
@ -991,6 +1007,9 @@ bool QFileInfo::isNativePath() const
|
||||
link to a file. Returns \c false if the
|
||||
object points to something which isn't a file, such as a directory.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is a
|
||||
regular file (not the symlink).
|
||||
|
||||
\sa isDir(), isSymLink(), isBundle()
|
||||
*/
|
||||
bool QFileInfo::isFile() const
|
||||
@ -1006,6 +1025,9 @@ bool QFileInfo::isFile() const
|
||||
Returns \c true if this object points to a directory or to a symbolic
|
||||
link to a directory; otherwise returns \c false.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is a
|
||||
directory (not the symlink).
|
||||
|
||||
\sa isFile(), isSymLink(), isBundle()
|
||||
*/
|
||||
bool QFileInfo::isDir() const
|
||||
@ -1023,6 +1045,9 @@ bool QFileInfo::isDir() const
|
||||
Returns \c true if this object points to a bundle or to a symbolic
|
||||
link to a bundle on \macos and iOS; otherwise returns \c false.
|
||||
|
||||
If the file is a symlink, this function returns true if the target is a
|
||||
bundle (not the symlink).
|
||||
|
||||
\sa isDir(), isSymLink(), isFile()
|
||||
*/
|
||||
bool QFileInfo::isBundle() const
|
||||
@ -1044,7 +1069,8 @@ bool QFileInfo::isBundle() const
|
||||
the \l{symLinkTarget()}{link's target}.
|
||||
|
||||
In addition, true will be returned for shortcuts (\c *.lnk files) on
|
||||
Windows. Opening those will open the \c .lnk file itself.
|
||||
Windows. This behavior is deprecated and will likely change in a future
|
||||
version of Qt. Opening those will open the \c .lnk file itself.
|
||||
|
||||
Example:
|
||||
|
||||
@ -1190,6 +1216,9 @@ QString QFileInfo::symLinkTarget() const
|
||||
milliseconds). On Windows, it will return an empty string unless
|
||||
the \l{NTFS permissions} check has been enabled.
|
||||
|
||||
If the file is a symlink, this function returns the owner of the target
|
||||
(not the symlink).
|
||||
|
||||
\sa ownerId(), group(), groupId()
|
||||
*/
|
||||
QString QFileInfo::owner() const
|
||||
@ -1206,6 +1235,9 @@ QString QFileInfo::owner() const
|
||||
On Windows and on systems where files do not have owners this
|
||||
function returns ((uint) -2).
|
||||
|
||||
If the file is a symlink, this function returns the id of the owner of the target
|
||||
(not the symlink).
|
||||
|
||||
\sa owner(), group(), groupId()
|
||||
*/
|
||||
uint QFileInfo::ownerId() const
|
||||
@ -1225,6 +1257,9 @@ uint QFileInfo::ownerId() const
|
||||
This function can be time consuming under Unix (in the order of
|
||||
milliseconds).
|
||||
|
||||
If the file is a symlink, this function returns the owning group of the
|
||||
target (not the symlink).
|
||||
|
||||
\sa groupId(), owner(), ownerId()
|
||||
*/
|
||||
QString QFileInfo::group() const
|
||||
@ -1241,6 +1276,9 @@ QString QFileInfo::group() const
|
||||
On Windows and on systems where files do not have groups this
|
||||
function always returns (uint) -2.
|
||||
|
||||
If the file is a symlink, this function returns the id of the group owning the
|
||||
target (not the symlink).
|
||||
|
||||
\sa group(), owner(), ownerId()
|
||||
*/
|
||||
uint QFileInfo::groupId() const
|
||||
@ -1266,6 +1304,9 @@ uint QFileInfo::groupId() const
|
||||
Example:
|
||||
\snippet code/src_corelib_io_qfileinfo.cpp 10
|
||||
|
||||
If the file is a symlink, this function checks the permissions of the
|
||||
target (not the symlink).
|
||||
|
||||
\sa isReadable(), isWritable(), isExecutable()
|
||||
*/
|
||||
bool QFileInfo::permission(QFile::Permissions permissions) const
|
||||
@ -1288,6 +1329,9 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
|
||||
|
||||
\note The result might be inaccurate on Windows if the
|
||||
\l{NTFS permissions} check has not been enabled.
|
||||
|
||||
If the file is a symlink, this function returns the permissions of the
|
||||
target (not the symlink).
|
||||
*/
|
||||
QFile::Permissions QFileInfo::permissions() const
|
||||
{
|
||||
@ -1305,6 +1349,9 @@ QFile::Permissions QFileInfo::permissions() const
|
||||
Returns the file size in bytes. If the file does not exist or cannot be
|
||||
fetched, 0 is returned.
|
||||
|
||||
If the file is a symlink, the size of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa exists()
|
||||
*/
|
||||
qint64 QFileInfo::size() const
|
||||
@ -1334,6 +1381,9 @@ qint64 QFileInfo::size() const
|
||||
the time the file was created, metadataChangeTime() to get the time its
|
||||
metadata was last changed, or lastModified() to get the time it was last modified.
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
|
||||
*/
|
||||
QDateTime QFileInfo::created() const
|
||||
@ -1352,6 +1402,9 @@ QDateTime QFileInfo::created() const
|
||||
If the file birth time is not available, this function returns an invalid
|
||||
QDateTime.
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa lastModified(), lastRead(), metadataChangeTime()
|
||||
*/
|
||||
QDateTime QFileInfo::birthTime() const
|
||||
@ -1366,6 +1419,9 @@ QDateTime QFileInfo::birthTime() const
|
||||
user writes or sets inode information (for example, changing the file
|
||||
permissions).
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa lastModified(), lastRead()
|
||||
*/
|
||||
QDateTime QFileInfo::metadataChangeTime() const
|
||||
@ -1376,6 +1432,9 @@ QDateTime QFileInfo::metadataChangeTime() const
|
||||
/*!
|
||||
Returns the date and local time when the file was last modified.
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
|
||||
*/
|
||||
QDateTime QFileInfo::lastModified() const
|
||||
@ -1389,6 +1448,9 @@ QDateTime QFileInfo::lastModified() const
|
||||
On platforms where this information is not available, returns the
|
||||
same as lastModified().
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
|
||||
*/
|
||||
QDateTime QFileInfo::lastRead() const
|
||||
@ -1402,6 +1464,9 @@ QDateTime QFileInfo::lastRead() const
|
||||
Returns the file time specified by \a time. If the time cannot be
|
||||
determined, an invalid date time is returned.
|
||||
|
||||
If the file is a symlink, the time of the target file is returned
|
||||
(not the symlink).
|
||||
|
||||
\sa QFile::FileTime, QDateTime::isValid()
|
||||
*/
|
||||
QDateTime QFileInfo::fileTime(QFile::FileTime time) const
|
||||
|
@ -69,7 +69,9 @@ static bool checkNameDecodable(const char *d_name, qsizetype len)
|
||||
# ifdef QT_LOCALE_IS_UTF8
|
||||
int mibEnum = 106;
|
||||
# else
|
||||
int mibEnum = codec->mibEnum();
|
||||
int mibEnum = 4; // Latin 1
|
||||
if (codec)
|
||||
mibEnum = codec->mibEnum();
|
||||
# endif
|
||||
if (Q_LIKELY(mibEnum == 106)) // UTF-8
|
||||
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;
|
||||
|
@ -423,7 +423,7 @@ bool QEventDispatcherCoreFoundation::processPostedEvents()
|
||||
m_processEvents.processedPostedEvents = true;
|
||||
|
||||
qCDebug(lcEventDispatcher) << "Sending posted events for"
|
||||
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
|
||||
<< QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
|
||||
QCoreApplication::sendPostedEvents();
|
||||
|
||||
return true;
|
||||
|
@ -376,6 +376,38 @@ static quint64 detectProcessorFeatures()
|
||||
features &= ~AllAVX512;
|
||||
}
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
/**
|
||||
* Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
|
||||
* failing random generation instruction, which always returns
|
||||
* 0xffffffff, even when generation was "successful".
|
||||
*
|
||||
* This code checks if hardware random generator generates four consecutive
|
||||
* equal numbers. If it does, then we probably have a failing one and
|
||||
* should disable it completely.
|
||||
*
|
||||
* https://bugreports.qt.io/browse/QTBUG-69423
|
||||
*/
|
||||
if (features & CpuFeatureRDRND) {
|
||||
const qsizetype testBufferSize = 4;
|
||||
unsigned testBuffer[4] = {};
|
||||
|
||||
const qsizetype generated = qRandomCpu(testBuffer, testBufferSize);
|
||||
|
||||
if (Q_UNLIKELY(generated == testBufferSize &&
|
||||
testBuffer[0] == testBuffer[1] &&
|
||||
testBuffer[1] == testBuffer[2] &&
|
||||
testBuffer[2] == testBuffer[3])) {
|
||||
|
||||
fprintf(stderr, "WARNING: CPU random generator seem to be failing, disable hardware random number generation\n");
|
||||
fprintf(stderr, "WARNING: RDRND generated: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
testBuffer[0], testBuffer[1], testBuffer[2], testBuffer[3]);
|
||||
|
||||
features &= ~CpuFeatureRDRND;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
@ -590,4 +622,40 @@ void qDumpCPUFeatures()
|
||||
puts("");
|
||||
}
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
|
||||
# ifdef Q_PROCESSOR_X86_64
|
||||
# define _rdrandXX_step _rdrand64_step
|
||||
# else
|
||||
# define _rdrandXX_step _rdrand32_step
|
||||
# endif
|
||||
|
||||
QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
|
||||
{
|
||||
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
|
||||
unsigned *end = ptr + count;
|
||||
int retries = 10;
|
||||
|
||||
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
|
||||
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
|
||||
ptr += sizeof(qregisteruint)/sizeof(*ptr);
|
||||
else if (--retries == 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
|
||||
bool ok = _rdrand32_step(ptr);
|
||||
if (!ok && --retries)
|
||||
continue;
|
||||
if (ok)
|
||||
++ptr;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ptr - reinterpret_cast<unsigned *>(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -346,6 +346,15 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
|
||||
#endif
|
||||
Q_CORE_EXPORT quint64 qDetectCpuFeatures();
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept;
|
||||
#else
|
||||
static inline qsizetype qRandomCpu(void *, qsizetype) noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline quint64 qCpuFeatures()
|
||||
{
|
||||
quint64 features = qt_cpu_features[0].loadRelaxed();
|
||||
@ -362,6 +371,15 @@ static inline quint64 qCpuFeatures()
|
||||
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|
||||
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
|
||||
|
||||
inline bool qHasHwrng()
|
||||
{
|
||||
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
|
||||
return qCpuHasFeature(RDRND);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
|
||||
for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
|
||||
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
|
||||
{
|
||||
resize(list.size());
|
||||
resize(int(list.size())); // ### q6sizetype
|
||||
std::copy(list.begin(), list.end(),
|
||||
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
|
||||
return *this;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QSaveFile>
|
||||
#include <QCoreApplication>
|
||||
#include <QLoggingCategory>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
@ -54,7 +55,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
|
||||
Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
|
||||
|
||||
#ifndef GL_CONTEXT_LOST
|
||||
#define GL_CONTEXT_LOST 0x0507
|
||||
@ -64,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
|
||||
#define GL_PROGRAM_BINARY_LENGTH 0x8741
|
||||
#endif
|
||||
|
||||
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
|
||||
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
|
||||
#endif
|
||||
|
||||
const quint32 BINSHADER_MAGIC = 0x5174;
|
||||
const quint32 BINSHADER_VERSION = 0x3;
|
||||
const quint32 BINSHADER_QTVERSION = QT_VERSION;
|
||||
@ -123,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
|
||||
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
|
||||
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
|
||||
}
|
||||
qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
|
||||
}
|
||||
|
||||
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
|
||||
@ -154,24 +159,24 @@ static inline QByteArray readStr(const uchar **p)
|
||||
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
|
||||
{
|
||||
if (buf.size() < BASE_HEADER_SIZE) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Cached size too small");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
|
||||
return false;
|
||||
}
|
||||
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
|
||||
if (readUInt(&p) != BINSHADER_MAGIC) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Magic does not match");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
|
||||
return false;
|
||||
}
|
||||
if (readUInt(&p) != BINSHADER_VERSION) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Version does not match");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
|
||||
return false;
|
||||
}
|
||||
if (readUInt(&p) != BINSHADER_QTVERSION) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
|
||||
return false;
|
||||
}
|
||||
if (readUInt(&p) != sizeof(quintptr)) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -196,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
|
||||
|
||||
GLenum err = funcs->glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
|
||||
"format 0x%x, err = 0x%x",
|
||||
programId, blobSize, blobFormat, err);
|
||||
return false;
|
||||
@ -204,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
|
||||
GLint linkStatus = 0;
|
||||
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus != GL_TRUE) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
|
||||
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
|
||||
programId, blobSize, blobFormat, linkStatus, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
|
||||
programId, blobSize, blobFormat, err);
|
||||
return true;
|
||||
}
|
||||
@ -318,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
|
||||
if (vendor != info.glvendor) {
|
||||
// readStr returns non-null terminated strings just pointing to inside
|
||||
// 'p' so must print these via the stream qCDebug and not constData().
|
||||
qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
|
||||
qCDebug(lcOpenGLProgramDiskCache) << "GL_VENDOR does not match" << vendor << info.glvendor;
|
||||
undertaker.setActive();
|
||||
return false;
|
||||
}
|
||||
QByteArray renderer = readStr(&p);
|
||||
if (renderer != info.glrenderer) {
|
||||
qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
|
||||
qCDebug(lcOpenGLProgramDiskCache) << "GL_RENDERER does not match" << renderer << info.glrenderer;
|
||||
undertaker.setActive();
|
||||
return false;
|
||||
}
|
||||
QByteArray version = readStr(&p);
|
||||
if (version != info.glversion) {
|
||||
qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
|
||||
qCDebug(lcOpenGLProgramDiskCache) << "GL_VERSION does not match" << version << info.glversion;
|
||||
undertaker.setActive();
|
||||
return false;
|
||||
}
|
||||
@ -383,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
||||
|
||||
const int totalSize = headerSize + paddingSize + blobSize;
|
||||
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
|
||||
if (!blobSize)
|
||||
return;
|
||||
|
||||
@ -417,7 +422,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
||||
#endif
|
||||
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
|
||||
if (blobSize != outSize) {
|
||||
qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
|
||||
qCDebug(lcOpenGLProgramDiskCache, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -433,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
|
||||
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
if (f.write(blob) < blob.length())
|
||||
#endif
|
||||
qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
|
||||
} else {
|
||||
qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,4 +457,45 @@ void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *conte
|
||||
}
|
||||
#endif
|
||||
|
||||
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
|
||||
: QOpenGLSharedResource(context->shareGroup()),
|
||||
m_supported(false)
|
||||
{
|
||||
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via app attribute");
|
||||
return;
|
||||
}
|
||||
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via env var");
|
||||
return;
|
||||
}
|
||||
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
if (ctx) {
|
||||
if (ctx->isOpenGLES()) {
|
||||
qCDebug(lcOpenGLProgramDiskCache, "OpenGL ES v%d context", ctx->format().majorVersion());
|
||||
if (ctx->format().majorVersion() >= 3) {
|
||||
m_supported = true;
|
||||
} else {
|
||||
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "GL_OES_get_program_binary support = %d", hasExt);
|
||||
if (hasExt)
|
||||
m_supported = true;
|
||||
}
|
||||
} else {
|
||||
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "GL_ARB_get_program_binary support = %d", hasExt);
|
||||
if (hasExt)
|
||||
m_supported = true;
|
||||
}
|
||||
if (m_supported) {
|
||||
GLint fmtCount = 0;
|
||||
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Supported binary format count = %d", fmtCount);
|
||||
m_supported = fmtCount > 0;
|
||||
}
|
||||
}
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Shader cache supported = %d", m_supported);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -52,21 +52,26 @@
|
||||
//
|
||||
|
||||
#include <QtGui/qtguiglobal.h>
|
||||
#include <QtGui/qopenglshaderprogram.h>
|
||||
#include <QtCore/qcache.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtGui/private/qopenglcontext_p.h>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// These classes are also used by the OpenGL backend of QRhi. They must
|
||||
// therefore stay independent from QOpenGLShader(Program). Must rely only on
|
||||
// QOpenGLContext/Functions.
|
||||
|
||||
class QOpenGLProgramBinaryCache
|
||||
{
|
||||
public:
|
||||
struct ShaderDesc {
|
||||
ShaderDesc() { }
|
||||
ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
|
||||
: type(type), source(source)
|
||||
ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
|
||||
: stage(stage), source(source)
|
||||
{ }
|
||||
QOpenGLShader::ShaderType type;
|
||||
QShader::Stage stage;
|
||||
QByteArray source;
|
||||
};
|
||||
struct ProgramDesc {
|
||||
@ -104,6 +109,36 @@ private:
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
// While unlikely, one application can in theory use contexts with different versions
|
||||
// or profiles. Therefore any version- or extension-specific checks must be done on a
|
||||
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
|
||||
// although it's once-per-sharing-context-group, not per-context. Still, this should
|
||||
// be good enough in practice.
|
||||
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
|
||||
{
|
||||
public:
|
||||
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
|
||||
void invalidateResource() override { }
|
||||
void freeResource(QOpenGLContext *) override { }
|
||||
|
||||
bool isSupported() const { return m_supported; }
|
||||
|
||||
private:
|
||||
bool m_supported;
|
||||
};
|
||||
|
||||
class QOpenGLProgramBinarySupportCheckWrapper
|
||||
{
|
||||
public:
|
||||
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
|
||||
{
|
||||
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
|
||||
}
|
||||
|
||||
private:
|
||||
QOpenGLMultiGroupSharedResource m_resource;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
#include <QtCore/qvector.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtGui/qtransform.h>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QSurfaceFormat>
|
||||
@ -178,7 +177,7 @@ QT_BEGIN_NAMESPACE
|
||||
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
|
||||
*/
|
||||
|
||||
Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
|
||||
|
||||
// For GLES 3.1/3.2
|
||||
#ifndef GL_GEOMETRY_SHADER
|
||||
@ -209,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
|
||||
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
|
||||
#endif
|
||||
|
||||
#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
|
||||
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
|
||||
#endif
|
||||
|
||||
#ifndef QT_OPENGL_ES_2
|
||||
static inline bool isFormatGLES(const QSurfaceFormat &f)
|
||||
{
|
||||
@ -1080,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
|
||||
return addCacheableShaderFromSourceCode(type, QByteArray(source));
|
||||
}
|
||||
|
||||
static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
|
||||
{
|
||||
switch (type) {
|
||||
case QOpenGLShader::Vertex:
|
||||
return QShader::VertexStage;
|
||||
case QOpenGLShader::Fragment:
|
||||
return QShader::FragmentStage;
|
||||
case QOpenGLShader::Geometry:
|
||||
return QShader::GeometryStage;
|
||||
case QOpenGLShader::TessellationControl:
|
||||
return QShader::TessellationControlStage;
|
||||
case QOpenGLShader::TessellationEvaluation:
|
||||
return QShader::TessellationEvaluationStage;
|
||||
case QOpenGLShader::Compute:
|
||||
return QShader::ComputeStage;
|
||||
}
|
||||
return QShader::VertexStage;
|
||||
}
|
||||
|
||||
static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
|
||||
{
|
||||
switch (stage) {
|
||||
case QShader::VertexStage:
|
||||
return QOpenGLShader::Vertex;
|
||||
case QShader::TessellationControlStage:
|
||||
return QOpenGLShader::TessellationControl;
|
||||
case QShader::TessellationEvaluationStage:
|
||||
return QOpenGLShader::TessellationEvaluation;
|
||||
case QShader::GeometryStage:
|
||||
return QOpenGLShader::Geometry;
|
||||
case QShader::FragmentStage:
|
||||
return QOpenGLShader::Fragment;
|
||||
case QShader::ComputeStage:
|
||||
return QOpenGLShader::Compute;
|
||||
}
|
||||
return QOpenGLShader::Vertex;
|
||||
}
|
||||
|
||||
/*!
|
||||
\overload
|
||||
|
||||
@ -1108,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
|
||||
if (d->isCacheDisabled())
|
||||
return addShaderFromSourceCode(type, source);
|
||||
|
||||
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
|
||||
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1165,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
|
||||
if (d->isCacheDisabled())
|
||||
return addShaderFromSourceFile(type, fileName);
|
||||
|
||||
QOpenGLProgramBinaryCache::ShaderDesc shader(type);
|
||||
QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
|
||||
// NB! It could be tempting to defer reading the file contents and just
|
||||
// hash the filename as the cache key, perhaps combined with last-modified
|
||||
// timestamp checks. However, this would raise a number of issues (no
|
||||
@ -3719,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
|
||||
return true;
|
||||
}
|
||||
|
||||
// While unlikely, one application can in theory use contexts with different versions
|
||||
// or profiles. Therefore any version- or extension-specific checks must be done on a
|
||||
// per-context basis, not just once per process. QOpenGLSharedResource enables this,
|
||||
// although it's once-per-sharing-context-group, not per-context. Still, this should
|
||||
// be good enough in practice.
|
||||
class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
|
||||
{
|
||||
public:
|
||||
QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
|
||||
void invalidateResource() override { }
|
||||
void freeResource(QOpenGLContext *) override { }
|
||||
|
||||
bool isSupported() const { return m_supported; }
|
||||
|
||||
private:
|
||||
bool m_supported;
|
||||
};
|
||||
|
||||
QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
|
||||
: QOpenGLSharedResource(context->shareGroup()),
|
||||
m_supported(false)
|
||||
{
|
||||
if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
|
||||
return;
|
||||
}
|
||||
if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
|
||||
return;
|
||||
}
|
||||
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
if (ctx) {
|
||||
if (ctx->isOpenGLES()) {
|
||||
qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
|
||||
if (ctx->format().majorVersion() >= 3) {
|
||||
m_supported = true;
|
||||
} else {
|
||||
const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
|
||||
qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt);
|
||||
if (hasExt)
|
||||
m_supported = true;
|
||||
}
|
||||
} else {
|
||||
const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
|
||||
qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
|
||||
if (hasExt)
|
||||
m_supported = true;
|
||||
}
|
||||
if (m_supported) {
|
||||
GLint fmtCount = 0;
|
||||
ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
|
||||
qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
|
||||
m_supported = fmtCount > 0;
|
||||
}
|
||||
}
|
||||
qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
|
||||
}
|
||||
|
||||
class QOpenGLProgramBinarySupportCheckWrapper
|
||||
{
|
||||
public:
|
||||
QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
|
||||
{
|
||||
return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
|
||||
}
|
||||
|
||||
private:
|
||||
QOpenGLMultiGroupSharedResource m_resource;
|
||||
};
|
||||
|
||||
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
|
||||
{
|
||||
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
|
||||
@ -3800,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
|
||||
{
|
||||
Q_Q(QOpenGLShaderProgram);
|
||||
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
|
||||
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
|
||||
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
|
||||
if (!s->compileSourceCode(shader.source)) {
|
||||
log = s->log();
|
||||
return false;
|
||||
@ -3819,19 +3781,19 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
|
||||
Q_Q(QOpenGLShaderProgram);
|
||||
|
||||
const QByteArray cacheKey = binaryProgram.cacheKey();
|
||||
if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
|
||||
qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
|
||||
if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
|
||||
qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
|
||||
binaryProgram.shaders.count(), cacheKey.constData());
|
||||
|
||||
bool needsCompile = true;
|
||||
if (binCache.load(cacheKey, q->programId())) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
|
||||
needsCompile = false;
|
||||
}
|
||||
|
||||
bool needsSave = false;
|
||||
if (needsCompile) {
|
||||
qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
|
||||
if (compileCacheable())
|
||||
needsSave = true;
|
||||
else
|
||||
|
@ -34,7 +34,21 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qglobal.h>
|
||||
#ifndef CS_TDR_P_H
|
||||
#define CS_TDR_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of other Qt classes. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@ -207,3 +221,5 @@ const BYTE g_killDeviceByTimingOut[] =
|
||||
};
|
||||
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
#endif // CS_TDR_P_H
|
@ -1981,6 +1981,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const
|
||||
How the renderbuffer is implemented by a backend is not exposed to the
|
||||
applications. In some cases it may be backed by ordinary textures, while in
|
||||
others there may be a different kind of native resource used.
|
||||
|
||||
Renderbuffers that are used as (and are only used as) depth-stencil buffers
|
||||
in combination with a QRhiSwapChain's color buffers should have the
|
||||
UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
|
||||
depending on the backend and the underlying APIs, be more efficient, and
|
||||
QRhi provides automatic sizing behavior to match the color buffers, which
|
||||
means calling setPixelSize() and build() are not necessary for such
|
||||
renderbuffers.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -1996,12 +2004,15 @@ QRhiResource::Type QRhiBuffer::resourceType() const
|
||||
Flag values for flags() and setFlags()
|
||||
|
||||
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
|
||||
that the renderbuffer is only used in combination with a QRhiSwapChain and
|
||||
never in other ways. Relevant with some backends, while others ignore it.
|
||||
With OpenGL where a separate windowing system interface API is in use (EGL,
|
||||
GLX, etc.), the flag is important since it avoids creating any actual
|
||||
resource as there is already a windowing system provided depth/stencil
|
||||
buffer as requested by QSurfaceFormat.
|
||||
that the renderbuffer is only used in combination with a QRhiSwapChain, and
|
||||
never in any other way. This provides automatic sizing and resource
|
||||
rebuilding, so calling setPixelSize() or build() is not needed whenever
|
||||
this flag is set. This flag value may also trigger backend-specific
|
||||
behavior, for example with OpenGL, where a separate windowing system
|
||||
interface API is in use (EGL, GLX, etc.), the flag is especially important
|
||||
as it avoids creating any actual renderbuffer resource as there is already
|
||||
a windowing system provided depth/stencil buffer as requested by
|
||||
QSurfaceFormat.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -2523,16 +2534,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
|
||||
be used with the same pipeline, assuming the pipeline was built with one of
|
||||
them in the first place.
|
||||
|
||||
Creating and then using a new \c srb2 that is very similar to \c srb with
|
||||
the exception of referencing another texture could be implemented like the
|
||||
following:
|
||||
|
||||
\badcode
|
||||
srb2 = rhi->newShaderResourceBindings();
|
||||
QVector<QRhiShaderResourceBinding> bindings = srb->bindings();
|
||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler);
|
||||
srb2->setBindings(bindings);
|
||||
srb2->build();
|
||||
...
|
||||
cb->setGraphicsPipeline(ps);
|
||||
cb->setShaderResources(srb2); // binds srb2
|
||||
@ -2634,43 +2637,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
|
||||
\internal
|
||||
*/
|
||||
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
|
||||
: d(new QRhiShaderResourceBindingPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QRhiShaderResourceBinding::detach()
|
||||
{
|
||||
qAtomicDetach(d);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other)
|
||||
: d(other.d)
|
||||
{
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other)
|
||||
{
|
||||
qAtomicAssign(d, other.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destructor.
|
||||
*/
|
||||
QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
|
||||
{
|
||||
if (!d->ref.deref())
|
||||
delete d;
|
||||
// Zero out everything, including possible padding, because will use
|
||||
// qHashBits on it.
|
||||
memset(&d.u, 0, sizeof(d.u));
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2687,8 +2657,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
|
||||
*/
|
||||
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
|
||||
{
|
||||
return (d == other.d)
|
||||
|| (d->binding == other.d->binding && d->stage == other.d->stage && d->type == other.d->type);
|
||||
return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2701,15 +2670,13 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||
{
|
||||
QRhiShaderResourceBinding b;
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
||||
d->binding = binding;
|
||||
d->stage = stage;
|
||||
d->type = UniformBuffer;
|
||||
d->u.ubuf.buf = buf;
|
||||
d->u.ubuf.offset = 0;
|
||||
d->u.ubuf.maybeSize = 0; // entire buffer
|
||||
d->u.ubuf.hasDynamicOffset = false;
|
||||
b.d.binding = binding;
|
||||
b.d.stage = stage;
|
||||
b.d.type = UniformBuffer;
|
||||
b.d.u.ubuf.buf = buf;
|
||||
b.d.u.ubuf.offset = 0;
|
||||
b.d.u.ubuf.maybeSize = 0; // entire buffer
|
||||
b.d.u.ubuf.hasDynamicOffset = false;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2730,9 +2697,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
||||
{
|
||||
Q_ASSERT(size > 0);
|
||||
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->u.ubuf.offset = offset;
|
||||
d->u.ubuf.maybeSize = size;
|
||||
b.d.u.ubuf.offset = offset;
|
||||
b.d.u.ubuf.maybeSize = size;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2751,8 +2717,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
|
||||
int binding, StageFlags stage, QRhiBuffer *buf, int size)
|
||||
{
|
||||
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->u.ubuf.hasDynamicOffset = true;
|
||||
b.d.u.ubuf.hasDynamicOffset = true;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2765,13 +2730,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
|
||||
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
|
||||
{
|
||||
QRhiShaderResourceBinding b;
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
||||
d->binding = binding;
|
||||
d->stage = stage;
|
||||
d->type = SampledTexture;
|
||||
d->u.stex.tex = tex;
|
||||
d->u.stex.sampler = sampler;
|
||||
b.d.binding = binding;
|
||||
b.d.stage = stage;
|
||||
b.d.type = SampledTexture;
|
||||
b.d.u.stex.tex = tex;
|
||||
b.d.u.stex.sampler = sampler;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2787,13 +2750,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
|
||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||
{
|
||||
QRhiShaderResourceBinding b;
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
||||
d->binding = binding;
|
||||
d->stage = stage;
|
||||
d->type = ImageLoad;
|
||||
d->u.simage.tex = tex;
|
||||
d->u.simage.level = level;
|
||||
b.d.binding = binding;
|
||||
b.d.stage = stage;
|
||||
b.d.type = ImageLoad;
|
||||
b.d.u.simage.tex = tex;
|
||||
b.d.u.simage.level = level;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2809,8 +2770,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
|
||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||
{
|
||||
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->type = ImageStore;
|
||||
b.d.type = ImageStore;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2826,8 +2786,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
|
||||
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||
{
|
||||
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->type = ImageLoadStore;
|
||||
b.d.type = ImageLoadStore;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2841,14 +2800,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||
{
|
||||
QRhiShaderResourceBinding b;
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
Q_ASSERT(d->ref.loadRelaxed() == 1);
|
||||
d->binding = binding;
|
||||
d->stage = stage;
|
||||
d->type = BufferLoad;
|
||||
d->u.sbuf.buf = buf;
|
||||
d->u.sbuf.offset = 0;
|
||||
d->u.sbuf.maybeSize = 0; // entire buffer
|
||||
b.d.binding = binding;
|
||||
b.d.stage = stage;
|
||||
b.d.type = BufferLoad;
|
||||
b.d.u.sbuf.buf = buf;
|
||||
b.d.u.sbuf.offset = 0;
|
||||
b.d.u.sbuf.maybeSize = 0; // entire buffer
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2864,9 +2821,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
||||
{
|
||||
Q_ASSERT(size > 0);
|
||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->u.sbuf.offset = offset;
|
||||
d->u.sbuf.maybeSize = size;
|
||||
b.d.u.sbuf.offset = offset;
|
||||
b.d.u.sbuf.maybeSize = size;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2880,8 +2836,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||
{
|
||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->type = BufferStore;
|
||||
b.d.type = BufferStore;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2897,9 +2852,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
||||
{
|
||||
Q_ASSERT(size > 0);
|
||||
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->u.sbuf.offset = offset;
|
||||
d->u.sbuf.maybeSize = size;
|
||||
b.d.u.sbuf.offset = offset;
|
||||
b.d.u.sbuf.maybeSize = size;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2913,8 +2867,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||
{
|
||||
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->type = BufferLoadStore;
|
||||
b.d.type = BufferLoadStore;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2930,9 +2883,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
||||
{
|
||||
Q_ASSERT(size > 0);
|
||||
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
|
||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||
d->u.sbuf.offset = offset;
|
||||
d->u.sbuf.maybeSize = size;
|
||||
b.d.u.sbuf.offset = offset;
|
||||
b.d.u.sbuf.maybeSize = size;
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -2948,28 +2900,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
||||
*/
|
||||
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
|
||||
{
|
||||
if (a.d == b.d)
|
||||
const QRhiShaderResourceBinding::Data *da = a.data();
|
||||
const QRhiShaderResourceBinding::Data *db = b.data();
|
||||
|
||||
if (da == db)
|
||||
return true;
|
||||
|
||||
if (a.d->binding != b.d->binding
|
||||
|| a.d->stage != b.d->stage
|
||||
|| a.d->type != b.d->type)
|
||||
|
||||
if (da->binding != db->binding
|
||||
|| da->stage != db->stage
|
||||
|| da->type != db->type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (a.d->type) {
|
||||
switch (da->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
if (a.d->u.ubuf.buf != b.d->u.ubuf.buf
|
||||
|| a.d->u.ubuf.offset != b.d->u.ubuf.offset
|
||||
|| a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize)
|
||||
if (da->u.ubuf.buf != db->u.ubuf.buf
|
||||
|| da->u.ubuf.offset != db->u.ubuf.offset
|
||||
|| da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QRhiShaderResourceBinding::SampledTexture:
|
||||
if (a.d->u.stex.tex != b.d->u.stex.tex
|
||||
|| a.d->u.stex.sampler != b.d->u.stex.sampler)
|
||||
if (da->u.stex.tex != db->u.stex.tex
|
||||
|| da->u.stex.sampler != db->u.stex.sampler)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2979,8 +2935,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
||||
case QRhiShaderResourceBinding::ImageStore:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||
if (a.d->u.simage.tex != b.d->u.simage.tex
|
||||
|| a.d->u.simage.level != b.d->u.simage.level)
|
||||
if (da->u.simage.tex != db->u.simage.tex
|
||||
|| da->u.simage.level != db->u.simage.level)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2990,9 +2946,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
||||
case QRhiShaderResourceBinding::BufferStore:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||
if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
|
||||
|| a.d->u.sbuf.offset != b.d->u.sbuf.offset
|
||||
|| a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
|
||||
if (da->u.sbuf.buf != db->u.sbuf.buf
|
||||
|| da->u.sbuf.offset != db->u.sbuf.offset
|
||||
|| da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -3023,16 +2979,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
||||
*/
|
||||
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
|
||||
{
|
||||
const char *u = reinterpret_cast<const char *>(&b.d->u);
|
||||
return seed + uint(b.d->binding) + 10 * uint(b.d->stage) + 100 * uint(b.d->type)
|
||||
+ qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed);
|
||||
const QRhiShaderResourceBinding::Data *d = b.data();
|
||||
return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type)
|
||||
+ qHashBits(&d->u, sizeof(d->u), seed);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
||||
{
|
||||
const QRhiShaderResourceBindingPrivate *d = b.d;
|
||||
QDebugStateSaver saver(dbg);
|
||||
const QRhiShaderResourceBinding::Data *d = b.data();
|
||||
dbg.nospace() << "QRhiShaderResourceBinding("
|
||||
<< "binding=" << d->binding
|
||||
<< " stage=" << d->stage
|
||||
@ -3100,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const QVarLengthArray<QRhiShaderResourceBinding, 8> &bindings)
|
||||
{
|
||||
return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
|
||||
{
|
||||
QDebugStateSaver saver(dbg);
|
||||
@ -3351,7 +3312,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
|
||||
{
|
||||
sc = rhi->newSwapChain();
|
||||
ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||
QSize(), // no need to set the size yet
|
||||
QSize(), // no need to set the size here due to UsedWithSwapChainOnly
|
||||
1,
|
||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||
sc->setWindow(window);
|
||||
@ -3363,9 +3324,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
|
||||
|
||||
void resizeSwapChain()
|
||||
{
|
||||
const QSize outputSize = sc->surfacePixelSize();
|
||||
ds->setPixelSize(outputSize);
|
||||
ds->build();
|
||||
hasSwapChain = sc->buildOrResize();
|
||||
}
|
||||
|
||||
@ -3559,10 +3517,24 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
|
||||
\return The size of the window's associated surface or layer. Do not assume
|
||||
this is the same as QWindow::size() * QWindow::devicePixelRatio().
|
||||
|
||||
Can be called before buildOrResize() (but with window() already set), which
|
||||
allows setting the correct size for the depth-stencil buffer that is then
|
||||
used together with the swapchain's color buffers. Also used in combination
|
||||
with currentPixelSize() to detect size changes.
|
||||
\note Can also be called before buildOrResize(), if at least window() is
|
||||
already set) This in combination with currentPixelSize() allows to detect
|
||||
when a swapchain needs to be resized. However, watch out for the fact that
|
||||
the size of the underlying native object (surface, layer, or similar) is
|
||||
"live", so whenever this function is called, it returns the latest value
|
||||
reported by the underlying implementation, without any atomicity guarantee.
|
||||
Therefore, using this function to determine pixel sizes for graphics
|
||||
resources that are used in a frame is strongly discouraged. Rely on
|
||||
currentPixelSize() instead which returns a size that is atomic and will not
|
||||
change between buildOrResize() invocations.
|
||||
|
||||
\note For depth-stencil buffers used in combination with the swapchain's
|
||||
color buffers, it is strongly recommended to rely on the automatic sizing
|
||||
and rebuilding behavior provided by the
|
||||
QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
|
||||
size via this function just to get a size that can be passed to
|
||||
QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
|
||||
atomicity as described above.
|
||||
|
||||
\sa currentPixelSize()
|
||||
*/
|
||||
@ -5541,7 +5513,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
|
||||
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
|
||||
const UsageState &state)
|
||||
{
|
||||
auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
|
||||
auto it = m_buffers.find(buf);
|
||||
if (it != m_buffers.end()) {
|
||||
if (it->access != *access) {
|
||||
const QByteArray name = buf->name();
|
||||
@ -5557,12 +5529,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc
|
||||
}
|
||||
|
||||
Buffer b;
|
||||
b.buf = buf;
|
||||
b.slot = slot;
|
||||
b.access = *access;
|
||||
b.stage = *stage;
|
||||
b.stateAtPassBegin = state; // first use -> initial state
|
||||
m_buffers.append(b);
|
||||
m_buffers.insert(buf, b);
|
||||
}
|
||||
|
||||
static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
|
||||
@ -5581,7 +5552,7 @@ static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess acces
|
||||
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
|
||||
const UsageState &state)
|
||||
{
|
||||
auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
|
||||
auto it = m_textures.find(tex);
|
||||
if (it != m_textures.end()) {
|
||||
if (it->access != *access) {
|
||||
// Different subresources of a texture may be used for both load
|
||||
@ -5605,11 +5576,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
|
||||
}
|
||||
|
||||
Texture t;
|
||||
t.tex = tex;
|
||||
t.access = *access;
|
||||
t.stage = *stage;
|
||||
t.stateAtPassBegin = state; // first use -> initial state
|
||||
m_textures.append(t);
|
||||
m_textures.insert(tex, t);
|
||||
}
|
||||
|
||||
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <QSize>
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector>
|
||||
#include <QVarLengthArray>
|
||||
#include <QThread>
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
@ -320,10 +321,6 @@ public:
|
||||
Q_DECLARE_FLAGS(StageFlags, StageFlag)
|
||||
|
||||
QRhiShaderResourceBinding();
|
||||
QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
|
||||
QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
|
||||
~QRhiShaderResourceBinding();
|
||||
void detach();
|
||||
|
||||
bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
|
||||
|
||||
@ -344,19 +341,49 @@ public:
|
||||
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
|
||||
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
||||
|
||||
struct Data
|
||||
{
|
||||
int binding;
|
||||
QRhiShaderResourceBinding::StageFlags stage;
|
||||
QRhiShaderResourceBinding::Type type;
|
||||
struct UniformBufferData {
|
||||
QRhiBuffer *buf;
|
||||
int offset;
|
||||
int maybeSize;
|
||||
bool hasDynamicOffset;
|
||||
};
|
||||
struct SampledTextureData {
|
||||
QRhiTexture *tex;
|
||||
QRhiSampler *sampler;
|
||||
};
|
||||
struct StorageImageData {
|
||||
QRhiTexture *tex;
|
||||
int level;
|
||||
};
|
||||
struct StorageBufferData {
|
||||
QRhiBuffer *buf;
|
||||
int offset;
|
||||
int maybeSize;
|
||||
};
|
||||
union {
|
||||
UniformBufferData ubuf;
|
||||
SampledTextureData stex;
|
||||
StorageImageData simage;
|
||||
StorageBufferData sbuf;
|
||||
} u;
|
||||
};
|
||||
|
||||
Data *data() { return &d; }
|
||||
const Data *data() const { return &d; }
|
||||
|
||||
private:
|
||||
QRhiShaderResourceBindingPrivate *d;
|
||||
friend class QRhiShaderResourceBindingPrivate;
|
||||
friend Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
|
||||
friend Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
|
||||
friend Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW;
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
|
||||
#endif
|
||||
Data d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
|
||||
|
||||
Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_MOVABLE_TYPE);
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW;
|
||||
@ -900,8 +927,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
|
||||
public:
|
||||
QRhiResource::Type resourceType() const override;
|
||||
|
||||
QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
|
||||
void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
|
||||
void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
|
||||
|
||||
template<typename InputIterator>
|
||||
void setBindings(InputIterator first, InputIterator last)
|
||||
{
|
||||
m_bindings.clear();
|
||||
std::copy(first, last, std::back_inserter(m_bindings));
|
||||
}
|
||||
|
||||
void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed
|
||||
{
|
||||
setBindings(bindings.cbegin(), bindings.cend());
|
||||
}
|
||||
|
||||
const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
|
||||
const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
|
||||
|
||||
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
|
||||
|
||||
@ -909,7 +950,7 @@ public:
|
||||
|
||||
protected:
|
||||
QRhiShaderResourceBindings(QRhiImplementation *rhi);
|
||||
QVector<QRhiShaderResourceBinding> m_bindings;
|
||||
QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
|
||||
#endif
|
||||
@ -1040,8 +1081,15 @@ public:
|
||||
FrontFace frontFace() const { return m_frontFace; }
|
||||
void setFrontFace(FrontFace f) { m_frontFace = f; }
|
||||
|
||||
QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
|
||||
void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
|
||||
void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
|
||||
template<typename InputIterator>
|
||||
void setTargetBlends(InputIterator first, InputIterator last)
|
||||
{
|
||||
m_targetBlends.clear();
|
||||
std::copy(first, last, std::back_inserter(m_targetBlends));
|
||||
}
|
||||
const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
|
||||
const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
|
||||
|
||||
bool hasDepthTest() const { return m_depthTest; }
|
||||
void setDepthTest(bool enable) { m_depthTest = enable; }
|
||||
@ -1073,8 +1121,19 @@ public:
|
||||
float lineWidth() const { return m_lineWidth; }
|
||||
void setLineWidth(float width) { m_lineWidth = width; }
|
||||
|
||||
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
|
||||
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
|
||||
void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
|
||||
template<typename InputIterator>
|
||||
void setShaderStages(InputIterator first, InputIterator last)
|
||||
{
|
||||
m_shaderStages.clear();
|
||||
std::copy(first, last, std::back_inserter(m_shaderStages));
|
||||
}
|
||||
void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed
|
||||
{
|
||||
setShaderStages(stages.cbegin(), stages.cend());
|
||||
}
|
||||
const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
|
||||
const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
|
||||
|
||||
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
|
||||
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
|
||||
@ -1093,7 +1152,7 @@ protected:
|
||||
Topology m_topology = Triangles;
|
||||
CullMode m_cullMode = None;
|
||||
FrontFace m_frontFace = CCW;
|
||||
QVector<TargetBlend> m_targetBlends;
|
||||
QVarLengthArray<TargetBlend, 8> m_targetBlends;
|
||||
bool m_depthTest = false;
|
||||
bool m_depthWrite = false;
|
||||
CompareOp m_depthOp = Less;
|
||||
@ -1104,7 +1163,7 @@ protected:
|
||||
quint32 m_stencilWriteMask = 0xFF;
|
||||
int m_sampleCount = 1;
|
||||
float m_lineWidth = 1.0f;
|
||||
QVector<QRhiShaderStage> m_shaderStages;
|
||||
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
|
||||
QRhiVertexInputLayout m_vertexInputLayout;
|
||||
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
||||
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
|
||||
|
@ -381,57 +381,6 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL
|
||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
|
||||
|
||||
class Q_GUI_EXPORT QRhiShaderResourceBindingPrivate
|
||||
{
|
||||
public:
|
||||
QRhiShaderResourceBindingPrivate()
|
||||
: ref(1)
|
||||
{
|
||||
}
|
||||
|
||||
QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other)
|
||||
: ref(1),
|
||||
binding(other->binding),
|
||||
stage(other->stage),
|
||||
type(other->type),
|
||||
u(other->u)
|
||||
{
|
||||
}
|
||||
|
||||
static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; }
|
||||
static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; }
|
||||
|
||||
QAtomicInt ref;
|
||||
int binding;
|
||||
QRhiShaderResourceBinding::StageFlags stage;
|
||||
QRhiShaderResourceBinding::Type type;
|
||||
struct UniformBufferData {
|
||||
QRhiBuffer *buf;
|
||||
int offset;
|
||||
int maybeSize;
|
||||
bool hasDynamicOffset;
|
||||
};
|
||||
struct SampledTextureData {
|
||||
QRhiTexture *tex;
|
||||
QRhiSampler *sampler;
|
||||
};
|
||||
struct StorageImageData {
|
||||
QRhiTexture *tex;
|
||||
int level;
|
||||
};
|
||||
struct StorageBufferData {
|
||||
QRhiBuffer *buf;
|
||||
int offset;
|
||||
int maybeSize;
|
||||
};
|
||||
union {
|
||||
UniformBufferData ubuf;
|
||||
SampledTextureData stex;
|
||||
StorageImageData simage;
|
||||
StorageBufferData sbuf;
|
||||
} u;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct QRhiBatchedBindings
|
||||
{
|
||||
@ -554,28 +503,32 @@ public:
|
||||
const UsageState &state);
|
||||
|
||||
struct Buffer {
|
||||
QRhiBuffer *buf;
|
||||
int slot;
|
||||
BufferAccess access;
|
||||
BufferStage stage;
|
||||
UsageState stateAtPassBegin;
|
||||
};
|
||||
const QVector<Buffer> *buffers() const { return &m_buffers; }
|
||||
|
||||
using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
|
||||
BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
|
||||
BufferIterator cendBuffers() const { return m_buffers.cend(); }
|
||||
|
||||
struct Texture {
|
||||
QRhiTexture *tex;
|
||||
TextureAccess access;
|
||||
TextureStage stage;
|
||||
UsageState stateAtPassBegin;
|
||||
};
|
||||
const QVector<Texture> *textures() const { return &m_textures; }
|
||||
|
||||
using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
|
||||
TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
|
||||
TextureIterator cendTextures() const { return m_textures.cend(); }
|
||||
|
||||
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||
|
||||
private:
|
||||
QVector<Buffer> m_buffers;
|
||||
QVector<Texture> m_textures;
|
||||
QHash<QRhiBuffer *, Buffer> m_buffers;
|
||||
QHash<QRhiTexture *, Texture> m_textures;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
#include "qrhid3d11_p_p.h"
|
||||
#include "qshader_p.h"
|
||||
#include "cs_tdr.h"
|
||||
#include "cs_tdr_p.h"
|
||||
#include <QWindow>
|
||||
#include <QOperatingSystemVersion>
|
||||
#include <qmath.h>
|
||||
@ -598,7 +598,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
||||
bool hasDynamicOffsetInSrb = false;
|
||||
bool srbUpdate = false;
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -1746,7 +1746,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
srbD->csUAVs.clear();
|
||||
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -3082,11 +3082,11 @@ bool QD3D11ShaderResourceBindings::build()
|
||||
if (!sortedBindings.isEmpty())
|
||||
release();
|
||||
|
||||
sortedBindings = m_bindings;
|
||||
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
||||
{
|
||||
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
|
||||
return a.data()->binding < b.data()->binding;
|
||||
});
|
||||
|
||||
boundResourceData.resize(sortedBindings.count());
|
||||
@ -3939,9 +3939,16 @@ bool QD3D11SwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||
m_depthStencil->setPixelSize(pixelSize);
|
||||
if (!m_depthStencil->build())
|
||||
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
|
||||
pixelSize.width(), pixelSize.height());
|
||||
} else {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
}
|
||||
}
|
||||
|
||||
currentFrameSlot = 0;
|
||||
|
@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
void release() override;
|
||||
bool build() override;
|
||||
|
||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
||||
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||
uint generation = 0;
|
||||
|
||||
// Keep track of the generation number of each referenced QRhi* to be able
|
||||
@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
BoundStorageBufferData sbuf;
|
||||
};
|
||||
};
|
||||
QVector<BoundResourceData> boundResourceData;
|
||||
QVarLengthArray<BoundResourceData, 8> boundResourceData;
|
||||
|
||||
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
|
||||
QRhiBatchedBindings<UINT> vsubufoffsets;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#include <QtGui/private/qopenglextensions_p.h>
|
||||
#include <QtGui/private/qopenglprogrambinarycache_p.h>
|
||||
#include <qmath.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -275,6 +276,8 @@ QT_BEGIN_NAMESPACE
|
||||
#define GL_POINT_SPRITE 0x8861
|
||||
#endif
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
|
||||
|
||||
/*!
|
||||
Constructs a new QRhiGles2InitParams.
|
||||
|
||||
@ -583,7 +586,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag
|
||||
|
||||
int QRhiGles2::ubufAlignment() const
|
||||
{
|
||||
return 256;
|
||||
// No real uniform buffers are used so no need to pretend there is any
|
||||
// alignment requirement.
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool QRhiGles2::isYUpInFramebuffer() const
|
||||
@ -863,7 +868,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
||||
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
|
||||
bool hasDynamicOffsetInSrb = false;
|
||||
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
// no BufUniformRead / AccessUniform because no real uniform buffers are used
|
||||
@ -2181,7 +2186,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
||||
{
|
||||
GLbitfield barriers = 0;
|
||||
QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]);
|
||||
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
|
||||
// we only care about after-write, not any other accesses, and
|
||||
// cannot tell if something was written in a shader several passes
|
||||
// ago: now the previously written resource may be used with an
|
||||
@ -2189,17 +2193,16 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
||||
// barrier in theory. Hence setting all barrier bits whenever
|
||||
// something previously written is used for the first time in a
|
||||
// subsequent pass.
|
||||
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
|
||||
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access);
|
||||
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
|
||||
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
|
||||
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|
||||
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
|
||||
{
|
||||
barriers |= GL_ALL_BARRIER_BITS;
|
||||
}
|
||||
}
|
||||
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
|
||||
for (const QRhiPassResourceTracker::Texture &t : *textures) {
|
||||
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access);
|
||||
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
|
||||
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
|
||||
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|
||||
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
|
||||
{
|
||||
@ -2301,7 +2304,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
|
||||
int texUnit = 0;
|
||||
|
||||
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
|
||||
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -2707,8 +2710,7 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
|
||||
}
|
||||
}
|
||||
|
||||
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
|
||||
QShaderDescription *desc, int *glslVersionUsed)
|
||||
QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
|
||||
{
|
||||
const QShader bakedShader = shaderStage.shader();
|
||||
QVector<int> versionsToTry;
|
||||
@ -2727,8 +2729,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
||||
QShaderVersion ver(v, QShaderVersion::GlslEs);
|
||||
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
|
||||
if (!source.isEmpty()) {
|
||||
if (glslVersionUsed)
|
||||
*glslVersionUsed = v;
|
||||
if (glslVersion)
|
||||
*glslVersion = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2757,8 +2759,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
||||
for (int v : versionsToTry) {
|
||||
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
|
||||
if (!source.isEmpty()) {
|
||||
if (glslVersionUsed)
|
||||
*glslVersionUsed = v;
|
||||
if (glslVersion)
|
||||
*glslVersion = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2766,8 +2768,15 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
||||
if (source.isEmpty()) {
|
||||
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
|
||||
<< ") in baked shader" << bakedShader;
|
||||
return false;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion)
|
||||
{
|
||||
const QByteArray source = shaderSource(shaderStage, glslVersion);
|
||||
if (source.isEmpty())
|
||||
return false;
|
||||
|
||||
GLuint shader;
|
||||
auto cacheIt = m_shaderCache.constFind(shaderStage);
|
||||
@ -2804,7 +2813,6 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
|
||||
|
||||
f->glAttachShader(program, shader);
|
||||
|
||||
*desc = bakedShader.description();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2859,6 +2867,68 @@ void QRhiGles2::gatherSamplers(GLuint program, const QShaderDescription::InOutVa
|
||||
}
|
||||
}
|
||||
|
||||
bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
|
||||
{
|
||||
static QOpenGLProgramBinarySupportCheckWrapper checker;
|
||||
return checker.get(ctx)->isSupported();
|
||||
}
|
||||
|
||||
static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
|
||||
|
||||
static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case QRhiShaderStage::Vertex:
|
||||
return QShader::VertexStage;
|
||||
case QRhiShaderStage::Fragment:
|
||||
return QShader::FragmentStage;
|
||||
case QRhiShaderStage::Compute:
|
||||
return QShader::ComputeStage;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
return QShader::VertexStage;
|
||||
}
|
||||
}
|
||||
|
||||
QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
|
||||
GLuint program, QByteArray *cacheKey)
|
||||
{
|
||||
QRhiGles2::DiskCacheResult result = QRhiGles2::DiskCacheMiss;
|
||||
QByteArray diskCacheKey;
|
||||
|
||||
if (isProgramBinaryDiskCacheEnabled()) {
|
||||
QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
|
||||
for (int i = 0; i < stageCount; ++i) {
|
||||
const QRhiShaderStage &stage(stages[i]);
|
||||
const QByteArray source = shaderSource(stage, nullptr);
|
||||
if (source.isEmpty())
|
||||
return QRhiGles2::DiskCacheError;
|
||||
binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(toShaderStage(stage.type()), source));
|
||||
}
|
||||
|
||||
diskCacheKey = binaryProgram.cacheKey();
|
||||
if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
|
||||
program, diskCacheKey.constData());
|
||||
result = QRhiGles2::DiskCacheHit;
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheKey)
|
||||
*cacheKey = diskCacheKey;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
|
||||
{
|
||||
if (isProgramBinaryDiskCacheEnabled()) {
|
||||
qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
|
||||
program, cacheKey.constData());
|
||||
qrhi_programBinaryCache.save(cacheKey, program);
|
||||
}
|
||||
}
|
||||
|
||||
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
||||
: QRhiBuffer(rhi, type, usage, size)
|
||||
{
|
||||
@ -3545,17 +3615,29 @@ bool QGles2GraphicsPipeline::build()
|
||||
|
||||
program = rhiD->f->glCreateProgram();
|
||||
|
||||
QByteArray diskCacheKey;
|
||||
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(m_shaderStages.constData(),
|
||||
m_shaderStages.count(),
|
||||
program,
|
||||
&diskCacheKey);
|
||||
if (diskCacheResult == QRhiGles2::DiskCacheError)
|
||||
return false;
|
||||
|
||||
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
|
||||
|
||||
QShaderDescription vsDesc;
|
||||
QShaderDescription fsDesc;
|
||||
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
||||
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
|
||||
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
|
||||
if (isVertex) {
|
||||
if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
|
||||
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
|
||||
return false;
|
||||
vsDesc = shaderStage.shader().description();
|
||||
} else if (isFragment) {
|
||||
if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
|
||||
if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
|
||||
return false;
|
||||
fsDesc = shaderStage.shader().description();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3564,9 +3646,12 @@ bool QGles2GraphicsPipeline::build()
|
||||
rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
|
||||
}
|
||||
|
||||
if (!rhiD->linkProgram(program))
|
||||
if (needsCompile && !rhiD->linkProgram(program))
|
||||
return false;
|
||||
|
||||
if (needsCompile)
|
||||
rhiD->trySaveToDiskCache(program, diskCacheKey);
|
||||
|
||||
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
|
||||
rhiD->gatherUniforms(program, ub, &uniforms);
|
||||
|
||||
@ -3627,11 +3712,24 @@ bool QGles2ComputePipeline::build()
|
||||
program = rhiD->f->glCreateProgram();
|
||||
QShaderDescription csDesc;
|
||||
|
||||
if (!rhiD->compileShader(program, m_shaderStage, &csDesc, nullptr))
|
||||
QByteArray diskCacheKey;
|
||||
QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(&m_shaderStage, 1, program, &diskCacheKey);
|
||||
if (diskCacheResult == QRhiGles2::DiskCacheError)
|
||||
return false;
|
||||
if (!rhiD->linkProgram(program))
|
||||
|
||||
const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
|
||||
|
||||
if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
|
||||
return false;
|
||||
|
||||
csDesc = m_shaderStage.shader().description();
|
||||
|
||||
if (needsCompile && !rhiD->linkProgram(program))
|
||||
return false;
|
||||
|
||||
if (needsCompile)
|
||||
rhiD->trySaveToDiskCache(program, diskCacheKey);
|
||||
|
||||
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
|
||||
rhiD->gatherUniforms(program, ub, &uniforms);
|
||||
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
|
||||
@ -3705,6 +3803,13 @@ bool QGles2SwapChain::buildOrResize()
|
||||
m_currentPixelSize = surfacePixelSize();
|
||||
pixelSize = m_currentPixelSize;
|
||||
|
||||
if (m_depthStencil && m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)
|
||||
&& m_depthStencil->pixelSize() != pixelSize)
|
||||
{
|
||||
m_depthStencil->setPixelSize(pixelSize);
|
||||
m_depthStencil->build();
|
||||
}
|
||||
|
||||
rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
|
||||
rt.d.pixelSize = pixelSize;
|
||||
rt.d.dpr = float(m_window->devicePixelRatio());
|
||||
|
@ -692,13 +692,23 @@ public:
|
||||
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
|
||||
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
|
||||
int effectiveSampleCount(int sampleCount) const;
|
||||
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
|
||||
QShaderDescription *desc, int *glslVersionUsed);
|
||||
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||
bool linkProgram(GLuint program);
|
||||
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
||||
QVector<QGles2UniformDescription> *dst);
|
||||
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
|
||||
QVector<QGles2SamplerDescription> *dst);
|
||||
bool isProgramBinaryDiskCacheEnabled() const;
|
||||
|
||||
enum DiskCacheResult {
|
||||
DiskCacheHit,
|
||||
DiskCacheMiss,
|
||||
DiskCacheError
|
||||
};
|
||||
DiskCacheResult tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
|
||||
GLuint program, QByteArray *cacheKey);
|
||||
void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
|
||||
|
||||
QOpenGLContext *ctx = nullptr;
|
||||
bool importedContext = false;
|
||||
|
@ -656,7 +656,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
||||
} res[KNOWN_STAGES];
|
||||
|
||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
{
|
||||
@ -875,7 +875,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
||||
|
||||
// do buffer writes, figure out if we need to rebind, and mark as in-use
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -1036,44 +1036,11 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
||||
}
|
||||
}
|
||||
|
||||
QSize safeOutputSize(QRhiMetal *rhiD, QMetalCommandBuffer *cbD)
|
||||
{
|
||||
QSize size = cbD->currentTarget->pixelSize();
|
||||
|
||||
// So now we have the issue that the texture (drawable) size may have
|
||||
// changed again since swapchain buildOrResize() was called. This can
|
||||
// happen for example when interactively resizing the window a lot in one
|
||||
// go, and command buffer building happens on a dedicated thread (f.ex.
|
||||
// using the threaded render loop of Qt Quick).
|
||||
//
|
||||
// This is only an issue when running in debug mode with XCode because Metal
|
||||
// validation will fail when setting viewport or scissor with the real size
|
||||
// being smaller than what we think it is. So query the drawable size right
|
||||
// here, in debug mode at least.
|
||||
//
|
||||
// In addition, we have to take the smaller of the two widths and heights
|
||||
// to be safe, apparently. In some cases validation seems to think that the
|
||||
// "render pass width" (or height) is the old(?) value.
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
if (cbD->currentTarget->resourceType() == QRhiResource::RenderTarget) {
|
||||
Q_ASSERT(rhiD->currentSwapChain);
|
||||
const QSize otherSize = rhiD->currentSwapChain->surfacePixelSize();
|
||||
size.setWidth(qMin(size.width(), otherSize.width()));
|
||||
size.setHeight(qMin(size.height(), otherSize.height()));
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(rhiD);
|
||||
#endif
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
||||
{
|
||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||
const QSize outputSize = safeOutputSize(this, cbD);
|
||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||
|
||||
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
|
||||
float x, y, w, h;
|
||||
@ -1105,7 +1072,7 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
|
||||
const QSize outputSize = safeOutputSize(this, cbD);
|
||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||
|
||||
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
|
||||
int x, y, w, h;
|
||||
@ -2801,21 +2768,21 @@ bool QMetalShaderResourceBindings::build()
|
||||
if (!sortedBindings.isEmpty())
|
||||
release();
|
||||
|
||||
sortedBindings = m_bindings;
|
||||
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
||||
{
|
||||
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
|
||||
return a.data()->binding < b.data()->binding;
|
||||
});
|
||||
if (!sortedBindings.isEmpty())
|
||||
maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding;
|
||||
maxBinding = sortedBindings.last().data()->binding;
|
||||
else
|
||||
maxBinding = -1;
|
||||
|
||||
boundResourceData.resize(sortedBindings.count());
|
||||
|
||||
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data();
|
||||
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -3529,20 +3496,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
|
||||
|
||||
QSize QMetalSwapChain::surfacePixelSize()
|
||||
{
|
||||
// may be called before build, must not access other than m_*
|
||||
|
||||
NSView *v = (NSView *) m_window->winId();
|
||||
if (v) {
|
||||
CAMetalLayer *layer = (CAMetalLayer *) [v layer];
|
||||
if (layer) {
|
||||
CGSize size = layer.bounds.size;
|
||||
size.width *= layer.contentsScale;
|
||||
size.height *= layer.contentsScale;
|
||||
layer.drawableSize = size;
|
||||
return QSize(int(size.width), int(size.height));
|
||||
}
|
||||
}
|
||||
return QSize();
|
||||
Q_ASSERT(m_window);
|
||||
return m_window->size() * m_window->devicePixelRatio();
|
||||
}
|
||||
|
||||
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
|
||||
@ -3593,8 +3548,9 @@ bool QMetalSwapChain::buildOrResize()
|
||||
return false;
|
||||
}
|
||||
|
||||
NSView *v = (NSView *) window->winId();
|
||||
d->layer = (CAMetalLayer *) [v layer];
|
||||
NSView *view = reinterpret_cast<NSView *>(window->winId());
|
||||
Q_ASSERT(view);
|
||||
d->layer = static_cast<CAMetalLayer *>(view.layer);
|
||||
Q_ASSERT(d->layer);
|
||||
|
||||
chooseFormats();
|
||||
@ -3623,7 +3579,15 @@ bool QMetalSwapChain::buildOrResize()
|
||||
d->layer.opaque = YES;
|
||||
}
|
||||
|
||||
m_currentPixelSize = surfacePixelSize();
|
||||
// Now set the layer's drawableSize which will stay set to the same value
|
||||
// until the next buildOrResize(), thus ensuring atomicity with regards to
|
||||
// the drawable size in frames.
|
||||
CGSize layerSize = d->layer.bounds.size;
|
||||
layerSize.width *= d->layer.contentsScale;
|
||||
layerSize.height *= d->layer.contentsScale;
|
||||
d->layer.drawableSize = layerSize;
|
||||
|
||||
m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize();
|
||||
pixelSize = m_currentPixelSize;
|
||||
|
||||
[d->layer setDevice: rhiD->d->dev];
|
||||
@ -3644,9 +3608,16 @@ bool QMetalSwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||
m_depthStencil->setPixelSize(pixelSize);
|
||||
if (!m_depthStencil->build())
|
||||
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
|
||||
pixelSize.width(), pixelSize.height());
|
||||
} else {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
}
|
||||
}
|
||||
|
||||
rtWrapper.d->pixelSize = pixelSize;
|
||||
|
@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
void release() override;
|
||||
bool build() override;
|
||||
|
||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
||||
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||
int maxBinding = -1;
|
||||
|
||||
struct BoundUniformBufferData {
|
||||
@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
BoundStorageBufferData sbuf;
|
||||
};
|
||||
};
|
||||
QVector<BoundResourceData> boundResourceData;
|
||||
QVarLengthArray<BoundResourceData, 8> boundResourceData;
|
||||
|
||||
uint generation = 0;
|
||||
friend class QRhiMetal;
|
||||
|
@ -2313,7 +2313,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
|
||||
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
|
||||
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
|
||||
|
||||
VkWriteDescriptorSet writeInfo;
|
||||
@ -3556,12 +3556,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
|
||||
if (tracker.isEmpty())
|
||||
return;
|
||||
|
||||
const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
|
||||
for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
|
||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf);
|
||||
VkAccessFlags access = toVkAccess(b.access);
|
||||
VkPipelineStageFlags stage = toVkPipelineStage(b.stage);
|
||||
QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin);
|
||||
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
|
||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
|
||||
VkAccessFlags access = toVkAccess(it->access);
|
||||
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
|
||||
QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin);
|
||||
if (!s.stage)
|
||||
continue;
|
||||
if (s.access == access && s.stage == stage) {
|
||||
@ -3575,7 +3574,7 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
|
||||
bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
bufMemBarrier.srcAccessMask = s.access;
|
||||
bufMemBarrier.dstAccessMask = access;
|
||||
bufMemBarrier.buffer = bufD->buffers[b.slot];
|
||||
bufMemBarrier.buffer = bufD->buffers[it->slot];
|
||||
bufMemBarrier.size = VK_WHOLE_SIZE;
|
||||
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
|
||||
0, nullptr,
|
||||
@ -3583,13 +3582,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
|
||||
0, nullptr);
|
||||
}
|
||||
|
||||
const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
|
||||
for (const QRhiPassResourceTracker::Texture &t : *textures) {
|
||||
QVkTexture *texD = QRHI_RES(QVkTexture, t.tex);
|
||||
VkImageLayout layout = toVkLayout(t.access);
|
||||
VkAccessFlags access = toVkAccess(t.access);
|
||||
VkPipelineStageFlags stage = toVkPipelineStage(t.stage);
|
||||
QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin);
|
||||
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
|
||||
QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
|
||||
VkImageLayout layout = toVkLayout(it->access);
|
||||
VkAccessFlags access = toVkAccess(it->access);
|
||||
VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
|
||||
QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin);
|
||||
if (s.access == access && s.stage == stage && s.layout == layout) {
|
||||
if (!accessIsWrite(access))
|
||||
continue;
|
||||
@ -3870,7 +3868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
bool hasDynamicOffsetInSrb = false;
|
||||
|
||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
|
||||
@ -3889,7 +3887,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
// Do host writes and mark referenced shader resources as in-use.
|
||||
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
|
||||
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
|
||||
switch (b->type) {
|
||||
@ -4022,7 +4020,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
// and neither srb nor dynamicOffsets has any such ordering
|
||||
// requirement.
|
||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||
if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
|
||||
uint32_t offset = 0;
|
||||
for (int i = 0; i < dynamicOffsetCount; ++i) {
|
||||
@ -4750,7 +4748,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic
|
||||
dst->compareOp = toVkCompareOp(src.compareOp);
|
||||
}
|
||||
|
||||
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b)
|
||||
static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
|
||||
{
|
||||
switch (b->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
@ -5697,16 +5695,17 @@ bool QVkShaderResourceBindings::build()
|
||||
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
||||
descSets[i] = VK_NULL_HANDLE;
|
||||
|
||||
sortedBindings = m_bindings;
|
||||
sortedBindings.clear();
|
||||
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
||||
{
|
||||
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
|
||||
return a.data()->binding < b.data()->binding;
|
||||
});
|
||||
|
||||
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
|
||||
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
|
||||
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
|
||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||
VkDescriptorSetLayoutBinding vkbinding;
|
||||
memset(&vkbinding, 0, sizeof(vkbinding));
|
||||
vkbinding.binding = uint32_t(b->binding);
|
||||
@ -6315,9 +6314,16 @@ bool QVkSwapChain::buildOrResize()
|
||||
m_depthStencil->sampleCount(), m_sampleCount);
|
||||
}
|
||||
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
|
||||
m_depthStencil->setPixelSize(pixelSize);
|
||||
if (!m_depthStencil->build())
|
||||
qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
|
||||
pixelSize.width(), pixelSize.height());
|
||||
} else {
|
||||
qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
|
||||
m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
|
||||
pixelSize.width(), pixelSize.height());
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_renderPassDesc)
|
||||
|
@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
void release() override;
|
||||
bool build() override;
|
||||
|
||||
QVector<QRhiShaderResourceBinding> sortedBindings;
|
||||
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
|
||||
int poolIndex = -1;
|
||||
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
||||
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
|
||||
@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
BoundStorageBufferData sbuf;
|
||||
};
|
||||
};
|
||||
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
||||
QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
||||
|
||||
friend class QRhiVulkan;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
@ -2096,10 +2096,11 @@ uint qHash(const QFont &font, uint seed) noexcept
|
||||
*/
|
||||
bool QFont::fromString(const QString &descrip)
|
||||
{
|
||||
const auto l = descrip.splitRef(QLatin1Char(','));
|
||||
|
||||
int count = l.count();
|
||||
if (!count || (count > 2 && count < 9) || count > 11) {
|
||||
const QStringRef sr = QStringRef(&descrip).trimmed();
|
||||
const auto l = sr.split(QLatin1Char(','));
|
||||
const int count = l.count();
|
||||
if (!count || (count > 2 && count < 9) || count > 11 ||
|
||||
l.first().isEmpty()) {
|
||||
qWarning("QFont::fromString: Invalid description '%s'",
|
||||
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
|
||||
return false;
|
||||
|
@ -467,6 +467,14 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
||||
if (fallbackList.isEmpty())
|
||||
return fallbackList;
|
||||
|
||||
// .Apple Symbols Fallback will be at the beginning of the list and we will
|
||||
// detect that this has glyphs for Arabic and other writing systems.
|
||||
// Since it is a symbol font, it should be the last resort, so that
|
||||
// the proper fonts for these writing systems are preferred.
|
||||
int symbolIndex = fallbackList.indexOf(QLatin1String(".Apple Symbols Fallback"));
|
||||
if (symbolIndex >= 0)
|
||||
fallbackList.move(symbolIndex, fallbackList.size() - 1);
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
// Since we are only returning a list of default fonts for the current language, we do not
|
||||
// cover all Unicode completely. This was especially an issue for some of the common script
|
||||
@ -481,6 +489,15 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
||||
fallbackList.append(QStringLiteral("Apple Symbols"));
|
||||
#endif
|
||||
|
||||
// Since iOS 13, the cascade list may contain meta-fonts which have not been
|
||||
// populated to the database, such as ".AppleJapaneseFont". It is important that we
|
||||
// include this in the fallback list, in order to get fallback support for all
|
||||
// languages
|
||||
for (const QString &fallback : fallbackList) {
|
||||
if (!QPlatformFontDatabase::isFamilyPopulated(fallback))
|
||||
const_cast<QCoreTextFontDatabase *>(this)->populateFamily(fallback);
|
||||
}
|
||||
|
||||
extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &);
|
||||
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);
|
||||
|
||||
|
@ -465,7 +465,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
|
||||
return QStringList(QLatin1String("android"));
|
||||
}
|
||||
return QStringList(QLatin1String("fusion"));
|
||||
|
||||
case DialogButtonBoxLayout:
|
||||
return QVariant(QPlatformDialogHelper::AndroidLayout);
|
||||
case MouseDoubleClickDistance:
|
||||
{
|
||||
int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
|
||||
@ -489,8 +490,6 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
|
||||
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case DialogButtonBoxLayout:
|
||||
return QVariant(QPlatformDialogHelper::AndroidLayout);
|
||||
default:
|
||||
return QPlatformTheme::themeHint(hint);
|
||||
}
|
||||
|
@ -881,7 +881,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
|
||||
return;
|
||||
}
|
||||
|
||||
int serial = serialNumber.load();
|
||||
int serial = serialNumber.loadRelaxed();
|
||||
if (!threadData->canWait || (serial != lastSerial)) {
|
||||
lastSerial = serial;
|
||||
QCoreApplication::sendPostedEvents();
|
||||
|
@ -43,9 +43,7 @@
|
||||
|
||||
- (void)initDrawing
|
||||
{
|
||||
self.wantsLayer = [self layerExplicitlyRequested]
|
||||
|| [self shouldUseMetalLayer]
|
||||
|| [self layerEnabledByMacOS];
|
||||
[self updateLayerBacking];
|
||||
|
||||
// Enable high-DPI OpenGL for retina displays. Enabling has the side
|
||||
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
||||
@ -71,22 +69,13 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
// ----------------------- Layer setup -----------------------
|
||||
|
||||
- (void)updateLayerBacking
|
||||
{
|
||||
Q_UNUSED(dirtyRect);
|
||||
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
|
||||
QRegion exposedRegion;
|
||||
const NSRect *dirtyRects;
|
||||
NSInteger numDirtyRects;
|
||||
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
|
||||
for (int i = 0; i < numDirtyRects; ++i)
|
||||
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
|
||||
|
||||
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
|
||||
m_platformWindow->handleExposeEvent(exposedRegion);
|
||||
self.wantsLayer = [self layerEnabledByMacOS]
|
||||
|| [self layerExplicitlyRequested]
|
||||
|| [self shouldUseMetalLayer];
|
||||
}
|
||||
|
||||
- (BOOL)layerEnabledByMacOS
|
||||
@ -123,40 +112,81 @@
|
||||
return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
|
||||
}
|
||||
|
||||
/*
|
||||
This method is called by AppKit when layer-backing is requested by
|
||||
setting wantsLayer too YES (via -[NSView _updateLayerBackedness]),
|
||||
or in cases where AppKit itself decides that a view should be
|
||||
layer-backed.
|
||||
|
||||
Note however that some code paths in AppKit will not go via this
|
||||
method for creating the backing layer, and will instead create the
|
||||
layer manually, and just call setLayer. An example of this is when
|
||||
an NSOpenGLContext is attached to a view, in which case AppKit will
|
||||
create a new layer in NSOpenGLContextSetLayerOnViewIfNecessary.
|
||||
|
||||
For this reason we leave the implementation of this override as
|
||||
minimal as possible, only focusing on creating the appropriate
|
||||
layer type, and then leave it up to setLayer to do the work of
|
||||
making sure the layer is set up correctly.
|
||||
*/
|
||||
- (CALayer *)makeBackingLayer
|
||||
{
|
||||
if ([self shouldUseMetalLayer]) {
|
||||
// Check if Metal is supported. If it isn't then it's most likely
|
||||
// too late at this point and the QWindow will be non-functional,
|
||||
// but we can at least print a warning.
|
||||
if (![MTLCreateSystemDefaultDevice() autorelease]) {
|
||||
qWarning() << "QWindow initialization error: Metal is not supported";
|
||||
return [super makeBackingLayer];
|
||||
if ([MTLCreateSystemDefaultDevice() autorelease]) {
|
||||
return [CAMetalLayer layer];
|
||||
} else {
|
||||
qCWarning(lcQpaDrawing) << "Failed to create QWindow::MetalSurface."
|
||||
<< "Metal is not supported by any of the GPUs in this system.";
|
||||
}
|
||||
|
||||
CAMetalLayer *layer = [CAMetalLayer layer];
|
||||
|
||||
// Set the contentsScale for the layer. This is normally done in
|
||||
// viewDidChangeBackingProperties, however on startup that function
|
||||
// is called before the layer is created here. The layer's drawableSize
|
||||
// is updated from layoutSublayersOfLayer as usual.
|
||||
layer.contentsScale = self.window.backingScaleFactor;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
return [super makeBackingLayer];
|
||||
}
|
||||
|
||||
/*
|
||||
This method is called by AppKit whenever the view is asked to change
|
||||
its layer, which can happen both as a result of enabling layer-backing,
|
||||
or when a layer is set explicitly. The latter can happen both when a
|
||||
view is layer-hosting, or when AppKit internals are switching out the
|
||||
layer-backed view, as described above for makeBackingLayer.
|
||||
*/
|
||||
- (void)setLayer:(CALayer *)layer
|
||||
{
|
||||
qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer
|
||||
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
|
||||
qCDebug(lcQpaDrawing) << "Making" << self
|
||||
<< (self.wantsLayer ? "layer-backed" : "layer-hosted")
|
||||
<< "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
|
||||
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
|
||||
|
||||
if (layer.delegate && layer.delegate != self) {
|
||||
qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate
|
||||
<< "This delegate is responsible for all view updates for" << self;
|
||||
} else {
|
||||
layer.delegate = self;
|
||||
}
|
||||
|
||||
[super setLayer:layer];
|
||||
layer.delegate = self;
|
||||
|
||||
// When adding a view to a view hierarchy the backing properties will change
|
||||
// which results in updating the contents scale, but in case of switching the
|
||||
// layer on a view that's already in a view hierarchy we need to manually ensure
|
||||
// the scale is up to date.
|
||||
if (self.superview)
|
||||
[self updateLayerContentsScale];
|
||||
|
||||
if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
|
||||
// If the view claims to be opaque we expect it to fill the entire
|
||||
// layer with content, in which case we want to detect any areas
|
||||
// where it doesn't.
|
||||
layer.backgroundColor = NSColor.magentaColor.CGColor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------- Layer updates -----------------------
|
||||
|
||||
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
|
||||
{
|
||||
// We need to set this explicitly since the super implementation
|
||||
@ -164,17 +194,95 @@
|
||||
return NSViewLayerContentsRedrawDuringViewResize;
|
||||
}
|
||||
|
||||
#if 0 // Disabled until we enable lazy backingstore resizing
|
||||
- (NSViewLayerContentsPlacement)layerContentsPlacement
|
||||
{
|
||||
// Always place the layer at top left without any automatic scaling,
|
||||
// so that we can re-use larger layers when resizing a window down.
|
||||
// Always place the layer at top left without any automatic scaling.
|
||||
// This will highlight situations where we're missing content for the
|
||||
// layer by not responding to the displayLayer: request synchronously.
|
||||
// It also allows us to re-use larger layers when resizing a window down.
|
||||
return NSViewLayerContentsPlacementTopLeft;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)viewDidChangeBackingProperties
|
||||
{
|
||||
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
|
||||
|
||||
if (self.layer)
|
||||
[self updateLayerContentsScale];
|
||||
|
||||
// Ideally we would plumb this situation through QPA in a way that lets
|
||||
// clients invalidate their own caches, recreate QBackingStore, etc.
|
||||
// For now we trigger an expose, and let QCocoaBackingStore deal with
|
||||
// buffer invalidation internally.
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)updateLayerContentsScale
|
||||
{
|
||||
// We expect clients to fill the layer with retina aware content,
|
||||
// based on the devicePixelRatio of the QWindow, so we set the
|
||||
// layer's content scale to match that. By going via devicePixelRatio
|
||||
// instead of applying the NSWindow's backingScaleFactor, we also take
|
||||
// into account OpenGL views with wantsBestResolutionOpenGLSurface set
|
||||
// to NO. In this case the window will have a backingScaleFactor of 2,
|
||||
// but the QWindow will have a devicePixelRatio of 1.
|
||||
auto devicePixelRatio = m_platformWindow->devicePixelRatio();
|
||||
qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio;
|
||||
self.layer.contentsScale = devicePixelRatio;
|
||||
}
|
||||
|
||||
/*
|
||||
This method is called by AppKit to determine whether it should update
|
||||
the contentScale of the layer to match the window backing scale.
|
||||
|
||||
We always return NO since we're updating the contents scale manually.
|
||||
*/
|
||||
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
|
||||
{
|
||||
Q_UNUSED(layer); Q_UNUSED(scale); Q_UNUSED(window);
|
||||
return NO;
|
||||
}
|
||||
|
||||
// ----------------------- Draw callbacks -----------------------
|
||||
|
||||
/*
|
||||
This method is called by AppKit for the non-layer case, where we are
|
||||
drawing into the NSWindow's surface.
|
||||
*/
|
||||
- (void)drawRect:(NSRect)dirtyBoundingRect
|
||||
{
|
||||
Q_ASSERT_X(!self.layer, "QNSView",
|
||||
"The drawRect code path should not be hit when we are layer backed");
|
||||
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
|
||||
QRegion exposedRegion;
|
||||
const NSRect *dirtyRects;
|
||||
NSInteger numDirtyRects;
|
||||
[self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
|
||||
for (int i = 0; i < numDirtyRects; ++i)
|
||||
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
|
||||
|
||||
if (exposedRegion.isEmpty())
|
||||
exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect();
|
||||
|
||||
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
|
||||
m_platformWindow->handleExposeEvent(exposedRegion);
|
||||
}
|
||||
|
||||
/*
|
||||
This method is called by AppKit when we are layer-backed, where
|
||||
we are drawing into the layer.
|
||||
*/
|
||||
- (void)displayLayer:(CALayer *)layer
|
||||
{
|
||||
Q_ASSERT_X(self.layer && layer == self.layer, "QNSView",
|
||||
"The displayLayer code path should only be hit for our own layer");
|
||||
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
|
||||
if (!NSThread.isMainThread) {
|
||||
// Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
|
||||
// which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
|
||||
@ -184,29 +292,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(layer == self.layer);
|
||||
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
|
||||
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
|
||||
|
||||
// FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
|
||||
m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
|
||||
}
|
||||
|
||||
- (void)viewDidChangeBackingProperties
|
||||
{
|
||||
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
|
||||
|
||||
if (self.layer)
|
||||
self.layer.contentsScale = self.window.backingScaleFactor;
|
||||
|
||||
// Ideally we would plumb this situation through QPA in a way that lets
|
||||
// clients invalidate their own caches, recreate QBackingStore, etc.
|
||||
// For now we trigger an expose, and let QCocoaBackingStore deal with
|
||||
// buffer invalidation internally.
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -891,13 +891,6 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
|
||||
result.profile = QSurfaceFormat::CoreProfile;
|
||||
else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||
result.profile = QSurfaceFormat::CompatibilityProfile;
|
||||
if (result.version < 0x0400)
|
||||
return result;
|
||||
// v4.0 onwards
|
||||
value = 0;
|
||||
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
|
||||
if (value == LOSE_CONTEXT_ON_RESET_ARB)
|
||||
result.options |= QSurfaceFormat::ResetNotification;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -975,6 +968,7 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
|
||||
*/
|
||||
|
||||
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
|
||||
#define ROBUSTNESS_EXTENSION "GL_ARB_robustness"
|
||||
|
||||
QOpenGLStaticContext::QOpenGLStaticContext() :
|
||||
vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
|
||||
@ -995,9 +989,31 @@ QOpenGLStaticContext::QOpenGLStaticContext() :
|
||||
wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
|
||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
|
||||
{
|
||||
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|
||||
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
|
||||
extensions |= SampleBuffers;
|
||||
if (defaultFormat.version < 0x0300) {
|
||||
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|
||||
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
|
||||
extensions |= SampleBuffers;
|
||||
if (extensionNames.startsWith(ROBUSTNESS_EXTENSION " ")
|
||||
|| extensionNames.indexOf(" " ROBUSTNESS_EXTENSION " ") != -1)
|
||||
extensions |= Robustness;
|
||||
} else {
|
||||
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
|
||||
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
|
||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
|
||||
if (glGetStringi) {
|
||||
GLint n = 0;
|
||||
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
||||
for (GLint i = 0; i < n; ++i) {
|
||||
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (p) {
|
||||
if (!strcmp(p, SAMPLE_BUFFER_EXTENSION))
|
||||
extensions |= SampleBuffers;
|
||||
else if (!strcmp(p, ROBUSTNESS_EXTENSION))
|
||||
extensions |= Robustness;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray QOpenGLStaticContext::getGlString(unsigned int which)
|
||||
@ -1236,27 +1252,11 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
|
||||
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
|
||||
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
|
||||
|
||||
bool hasRobustness = false;
|
||||
if (m_obtainedFormat.majorVersion() < 3) {
|
||||
const char *exts = reinterpret_cast<const char *>(QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS));
|
||||
hasRobustness = exts && strstr(exts, "GL_ARB_robustness");
|
||||
} else {
|
||||
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
|
||||
auto glGetStringi = reinterpret_cast<glGetStringi_t>(
|
||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
|
||||
if (glGetStringi) {
|
||||
GLint n = 0;
|
||||
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
||||
for (GLint i = 0; i < n; ++i) {
|
||||
const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (p && !strcmp(p, "GL_ARB_robustness")) {
|
||||
hasRobustness = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasRobustness) {
|
||||
if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) {
|
||||
GLint value = 0;
|
||||
QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value);
|
||||
if (value == LOSE_CONTEXT_ON_RESET_ARB)
|
||||
m_obtainedFormat.setOption(QSurfaceFormat::ResetNotification);
|
||||
m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
|
||||
reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ public:
|
||||
enum Extensions
|
||||
{
|
||||
SampleBuffers = 0x1,
|
||||
sRGBCapableFramebuffer = 0x2
|
||||
sRGBCapableFramebuffer = 0x2,
|
||||
Robustness = 0x4,
|
||||
};
|
||||
|
||||
typedef bool
|
||||
|
@ -2697,10 +2697,16 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
|
||||
return true;
|
||||
}
|
||||
if (localPos.y() < 0) {
|
||||
const int topResizeBarPos = -frameMargins().top();
|
||||
if (localPos.y() >= topResizeBarPos)
|
||||
// We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar,
|
||||
// otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262).
|
||||
// However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct
|
||||
// sizing frame height in all Windows versions/scales. This empirical constant seems to work, though.
|
||||
const int sizingHeight = 9;
|
||||
const int topResizeBarPos = sizingHeight - frameMargins().top();
|
||||
if (localPos.y() < topResizeBarPos) {
|
||||
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
|
||||
|
@ -79,7 +79,7 @@ QSqlDatabase db = QSqlDatabase::addDatabase("MYDRIVER");
|
||||
//! [3]
|
||||
...
|
||||
db = QSqlDatabase::addDatabase("QODBC");
|
||||
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
|
||||
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
|
||||
if (db.open()) {
|
||||
// success!
|
||||
}
|
||||
|
@ -2805,8 +2805,11 @@ template <> Q_TESTLIB_EXPORT char *QTest::toString<char>(const char &t)
|
||||
*/
|
||||
char *QTest::toString(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return nullptr;
|
||||
if (!str) {
|
||||
char *msg = new char[1];
|
||||
*msg = '\0';
|
||||
return msg;
|
||||
}
|
||||
char *msg = new char[strlen(str) + 1];
|
||||
return qstrcpy(msg, str);
|
||||
}
|
||||
|
@ -55,10 +55,14 @@
|
||||
#if QT_CONFIG(lineedit)
|
||||
#include "qlineedit.h"
|
||||
#endif
|
||||
#include <qpointer.h>
|
||||
#include "qpainter.h"
|
||||
#include "qwindow.h"
|
||||
#include "qpushbutton.h"
|
||||
#include "qset.h"
|
||||
#if QT_CONFIG(shortcut)
|
||||
# include "qshortcut.h"
|
||||
#endif
|
||||
#include "qstyle.h"
|
||||
#include "qvarlengtharray.h"
|
||||
#if defined(Q_OS_MACX)
|
||||
@ -232,31 +236,24 @@ void QWizardField::findProperty(const QWizardDefaultProperty *properties, int pr
|
||||
class QWizardLayoutInfo
|
||||
{
|
||||
public:
|
||||
inline QWizardLayoutInfo()
|
||||
: topLevelMarginLeft(-1), topLevelMarginRight(-1), topLevelMarginTop(-1),
|
||||
topLevelMarginBottom(-1), childMarginLeft(-1), childMarginRight(-1),
|
||||
childMarginTop(-1), childMarginBottom(-1), hspacing(-1), vspacing(-1),
|
||||
wizStyle(QWizard::ClassicStyle), header(false), watermark(false), title(false),
|
||||
subTitle(false), extension(false), sideWidget(false) {}
|
||||
|
||||
int topLevelMarginLeft;
|
||||
int topLevelMarginRight;
|
||||
int topLevelMarginTop;
|
||||
int topLevelMarginBottom;
|
||||
int childMarginLeft;
|
||||
int childMarginRight;
|
||||
int childMarginTop;
|
||||
int childMarginBottom;
|
||||
int hspacing;
|
||||
int vspacing;
|
||||
int buttonSpacing;
|
||||
QWizard::WizardStyle wizStyle;
|
||||
bool header;
|
||||
bool watermark;
|
||||
bool title;
|
||||
bool subTitle;
|
||||
bool extension;
|
||||
bool sideWidget;
|
||||
int topLevelMarginLeft = -1;
|
||||
int topLevelMarginRight = -1;
|
||||
int topLevelMarginTop = -1;
|
||||
int topLevelMarginBottom = -1;
|
||||
int childMarginLeft = -1;
|
||||
int childMarginRight = -1;
|
||||
int childMarginTop = -1;
|
||||
int childMarginBottom = -1;
|
||||
int hspacing = -1;
|
||||
int vspacing = -1;
|
||||
int buttonSpacing = -1;
|
||||
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
|
||||
bool header = false;
|
||||
bool watermark = false;
|
||||
bool title = false;
|
||||
bool subTitle = false;
|
||||
bool extension = false;
|
||||
bool sideWidget = false;
|
||||
|
||||
bool operator==(const QWizardLayoutInfo &other);
|
||||
inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
|
||||
@ -486,21 +483,18 @@ class QWizardPagePrivate : public QWidgetPrivate
|
||||
public:
|
||||
enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
|
||||
|
||||
inline QWizardPagePrivate()
|
||||
: wizard(0), completeState(Tri_Unknown), explicitlyFinal(false), commit(false) {}
|
||||
|
||||
bool cachedIsComplete() const;
|
||||
void _q_maybeEmitCompleteChanged();
|
||||
void _q_updateCachedCompleteState();
|
||||
|
||||
QWizard *wizard;
|
||||
QWizard *wizard = nullptr;
|
||||
QString title;
|
||||
QString subTitle;
|
||||
QPixmap pixmaps[QWizard::NPixmaps];
|
||||
QVector<QWizardField> pendingFields;
|
||||
mutable TriState completeState;
|
||||
bool explicitlyFinal;
|
||||
bool commit;
|
||||
mutable TriState completeState = Tri_Unknown;
|
||||
bool explicitlyFinal = false;
|
||||
bool commit = false;
|
||||
bool initialized = false;
|
||||
QMap<int, QString> buttonCustomTexts;
|
||||
};
|
||||
@ -556,42 +550,6 @@ public:
|
||||
Forward
|
||||
};
|
||||
|
||||
inline QWizardPrivate()
|
||||
: start(-1)
|
||||
, startSetByUser(false)
|
||||
, current(-1)
|
||||
, canContinue(false)
|
||||
, canFinish(false)
|
||||
, disableUpdatesCount(0)
|
||||
, wizStyle(QWizard::ClassicStyle)
|
||||
, opts(0)
|
||||
, buttonsHaveCustomLayout(false)
|
||||
, titleFmt(Qt::AutoText)
|
||||
, subTitleFmt(Qt::AutoText)
|
||||
, placeholderWidget1(0)
|
||||
, placeholderWidget2(0)
|
||||
, headerWidget(0)
|
||||
, watermarkLabel(0)
|
||||
, sideWidget(0)
|
||||
, pageFrame(0)
|
||||
, titleLabel(0)
|
||||
, subTitleLabel(0)
|
||||
, bottomRuler(0)
|
||||
#if QT_CONFIG(style_windowsvista)
|
||||
, vistaHelper(0)
|
||||
, vistaInitPending(true)
|
||||
, vistaState(QVistaHelper::Dirty)
|
||||
, vistaStateChanged(false)
|
||||
, inHandleAeroStyleChange(false)
|
||||
#endif
|
||||
, minimumWidth(0)
|
||||
, minimumHeight(0)
|
||||
, maximumWidth(QWIDGETSIZE_MAX)
|
||||
, maximumHeight(QWIDGETSIZE_MAX)
|
||||
{
|
||||
std::fill(btns, btns + QWizard::NButtons, static_cast<QAbstractButton *>(0));
|
||||
}
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
void cleanupPagesNotInHistory();
|
||||
@ -631,21 +589,21 @@ public:
|
||||
QMap<QString, int> fieldIndexMap;
|
||||
QVector<QWizardDefaultProperty> defaultPropertyTable;
|
||||
QList<int> history;
|
||||
int start;
|
||||
bool startSetByUser;
|
||||
int current;
|
||||
bool canContinue;
|
||||
bool canFinish;
|
||||
int start = -1;
|
||||
bool startSetByUser = false;
|
||||
int current = -1;
|
||||
bool canContinue = false;
|
||||
bool canFinish = false;
|
||||
QWizardLayoutInfo layoutInfo;
|
||||
int disableUpdatesCount;
|
||||
int disableUpdatesCount = 0;
|
||||
|
||||
QWizard::WizardStyle wizStyle;
|
||||
QWizard::WizardStyle wizStyle = QWizard::ClassicStyle;
|
||||
QWizard::WizardOptions opts;
|
||||
QMap<int, QString> buttonCustomTexts;
|
||||
bool buttonsHaveCustomLayout;
|
||||
bool buttonsHaveCustomLayout = false;
|
||||
QList<QWizard::WizardButton> buttonsCustomLayout;
|
||||
Qt::TextFormat titleFmt;
|
||||
Qt::TextFormat subTitleFmt;
|
||||
Qt::TextFormat titleFmt = Qt::AutoText;
|
||||
Qt::TextFormat subTitleFmt = Qt::AutoText;
|
||||
mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
|
||||
|
||||
union {
|
||||
@ -660,32 +618,35 @@ public:
|
||||
} btn;
|
||||
mutable QAbstractButton *btns[QWizard::NButtons];
|
||||
};
|
||||
QWizardAntiFlickerWidget *antiFlickerWidget;
|
||||
QWidget *placeholderWidget1;
|
||||
QWidget *placeholderWidget2;
|
||||
QWizardHeader *headerWidget;
|
||||
QWatermarkLabel *watermarkLabel;
|
||||
QWidget *sideWidget;
|
||||
QFrame *pageFrame;
|
||||
QLabel *titleLabel;
|
||||
QLabel *subTitleLabel;
|
||||
QWizardRuler *bottomRuler;
|
||||
QWizardAntiFlickerWidget *antiFlickerWidget = nullptr;
|
||||
QWidget *placeholderWidget1 = nullptr;
|
||||
QWidget *placeholderWidget2 = nullptr;
|
||||
QWizardHeader *headerWidget = nullptr;
|
||||
QWatermarkLabel *watermarkLabel = nullptr;
|
||||
QWidget *sideWidget = nullptr;
|
||||
QFrame *pageFrame = nullptr;
|
||||
QLabel *titleLabel = nullptr;
|
||||
QLabel *subTitleLabel = nullptr;
|
||||
QWizardRuler *bottomRuler = nullptr;
|
||||
|
||||
QVBoxLayout *pageVBoxLayout;
|
||||
QHBoxLayout *buttonLayout;
|
||||
QGridLayout *mainLayout;
|
||||
QVBoxLayout *pageVBoxLayout = nullptr;
|
||||
QHBoxLayout *buttonLayout = nullptr;
|
||||
QGridLayout *mainLayout = nullptr;
|
||||
|
||||
#if QT_CONFIG(style_windowsvista)
|
||||
QVistaHelper *vistaHelper;
|
||||
bool vistaInitPending;
|
||||
QVistaHelper::VistaState vistaState;
|
||||
bool vistaStateChanged;
|
||||
bool inHandleAeroStyleChange;
|
||||
QVistaHelper *vistaHelper = nullptr;
|
||||
# if QT_CONFIG(shortcut)
|
||||
QPointer<QShortcut> vistaNextShortcut;
|
||||
# endif
|
||||
bool vistaInitPending = true;
|
||||
QVistaHelper::VistaState vistaState = QVistaHelper::Dirty;
|
||||
bool vistaStateChanged = false;
|
||||
bool inHandleAeroStyleChange = false;
|
||||
#endif
|
||||
int minimumWidth;
|
||||
int minimumHeight;
|
||||
int maximumWidth;
|
||||
int maximumHeight;
|
||||
int minimumWidth = 0;
|
||||
int minimumHeight = 0;
|
||||
int maximumWidth = QWIDGETSIZE_MAX;
|
||||
int maximumHeight = QWIDGETSIZE_MAX;
|
||||
};
|
||||
|
||||
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
|
||||
@ -720,6 +681,8 @@ void QWizardPrivate::init()
|
||||
{
|
||||
Q_Q(QWizard);
|
||||
|
||||
std::fill(btns, btns + QWizard::NButtons, nullptr);
|
||||
|
||||
antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
|
||||
wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
|
||||
if (wizStyle == QWizard::MacStyle) {
|
||||
@ -1461,10 +1424,17 @@ void QWizardPrivate::updateButtonTexts()
|
||||
// Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
|
||||
// even in RTL mode, so do the same, even if it might be counter-intuitive.
|
||||
// The shortcut for 'back' is set in class QVistaBackButton.
|
||||
#if QT_CONFIG(shortcut)
|
||||
if (btns[QWizard::NextButton] && isVistaThemeEnabled())
|
||||
btns[QWizard::NextButton]->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Right));
|
||||
#endif
|
||||
#if QT_CONFIG(shortcut) && QT_CONFIG(style_windowsvista)
|
||||
if (btns[QWizard::NextButton] && isVistaThemeEnabled()) {
|
||||
if (vistaNextShortcut.isNull()) {
|
||||
vistaNextShortcut =
|
||||
new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right),
|
||||
btns[QWizard::NextButton], SLOT(animateClick()));
|
||||
}
|
||||
} else {
|
||||
delete vistaNextShortcut;
|
||||
}
|
||||
#endif // shortcut && style_windowsvista
|
||||
}
|
||||
|
||||
void QWizardPrivate::updateButtonLayout()
|
||||
|
@ -6204,7 +6204,7 @@ void QWidget::setFocusProxy(QWidget * w)
|
||||
|
||||
if (changingAppFocusWidget) {
|
||||
QWidget *newDeepestFocusProxy = d_func()->deepestFocusProxy();
|
||||
QApplicationPrivate::focus_widget = newDeepestFocusProxy ? newDeepestFocusProxy : this;
|
||||
QApplicationPrivate::setFocusWidget(newDeepestFocusProxy ? newDeepestFocusProxy : this, Qt::NoFocusReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5967,6 +5967,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
|
||||
case SP_ArrowLeft:
|
||||
icon = QIcon::fromTheme(QLatin1String("go-previous"));
|
||||
break;
|
||||
case SP_DialogNoButton:
|
||||
case SP_DialogCancelButton:
|
||||
icon = QIcon::fromTheme(QLatin1String("dialog-cancel"),
|
||||
QIcon::fromTheme(QLatin1String("process-stop")));
|
||||
|
@ -44,6 +44,9 @@ private slots:
|
||||
void fuzzyCompare();
|
||||
void rawNaN_data();
|
||||
void rawNaN();
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
void distinctNaN();
|
||||
#endif
|
||||
void generalNaN_data();
|
||||
void generalNaN();
|
||||
void infinity();
|
||||
@ -139,6 +142,9 @@ void tst_QNumeric::rawNaN_data()
|
||||
QTest::addColumn<double>("nan");
|
||||
|
||||
QTest::newRow("quiet") << qQNaN();
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
QTest::newRow("signaling") << qSNaN();
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QNumeric::rawNaN()
|
||||
@ -147,6 +153,15 @@ void tst_QNumeric::rawNaN()
|
||||
checkNaN(nan);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
void tst_QNumeric::distinctNaN()
|
||||
{
|
||||
const double qnan = qQNaN();
|
||||
const double snan = qSNaN();
|
||||
QVERIFY(memcmp(&qnan, &snan, sizeof(double)) != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QNumeric::generalNaN_data()
|
||||
{
|
||||
QTest::addColumn<int>("most");
|
||||
|
@ -320,7 +320,7 @@ void tst_QRandomGenerator::generate32_data()
|
||||
QTest::newRow("fixed") << (RandomValue32 & RandomDataMask);
|
||||
QTest::newRow("global") << 0U;
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
if (qt_has_hwrng())
|
||||
if (qHasHwrng())
|
||||
QTest::newRow("hwrng") << uint(UseSystemRNG);
|
||||
QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG);
|
||||
# ifdef HAVE_FALLBACK_ENGINE
|
||||
@ -755,7 +755,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data()
|
||||
|
||||
auto newRow = [&](quint32 max) {
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
if (qt_has_hwrng())
|
||||
if (qHasHwrng())
|
||||
QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max;
|
||||
QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max;
|
||||
# ifdef HAVE_FALLBACK_ENGINE
|
||||
@ -868,7 +868,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data()
|
||||
|
||||
auto newRow = [&](double min, double sup) {
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
if (qt_has_hwrng())
|
||||
if (qHasHwrng())
|
||||
QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup;
|
||||
QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup;
|
||||
# ifdef HAVE_FALLBACK_ENGINE
|
||||
|
@ -1413,10 +1413,12 @@ void tst_QCborValue::toCbor_data()
|
||||
// The rest of these tests are conversions whose decoding does not yield
|
||||
// back the same QCborValue.
|
||||
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
// Signalling NaN get normalized to quiet ones
|
||||
QTest::newRow("Double:snan") << QCborValue(qSNaN()) << raw("\xfb\x7f\xf8\0""\0\0\0\0\0") << QCborValue::EncodingOptions();
|
||||
QTest::newRow("Float:snan") << QCborValue(qSNaN()) << raw("\xfa\x7f\xc0\0\0") << QCborValue::EncodingOptions(QCborValue::UseFloat);
|
||||
QTest::newRow("Float16:snan") << QCborValue(qSNaN()) << raw("\xf9\x7e\0") << QCborValue::EncodingOptions(QCborValue::UseFloat16);
|
||||
#endif
|
||||
|
||||
// Floating point written as integers are read back as integers
|
||||
QTest::newRow("UseInteger:0") << QCborValue(0.) << raw("\x00") << QCborValue::EncodingOptions(QCborValue::UseIntegers);
|
||||
|
@ -3468,6 +3468,9 @@ void tst_QDateTime::timeZones() const
|
||||
|
||||
void tst_QDateTime::systemTimeZoneChange() const
|
||||
{
|
||||
#ifdef Q_OS_WINRT
|
||||
QSKIP("UWP applications cannot change the system`s time zone (sandboxing)");
|
||||
#endif
|
||||
// Set the timezone to Brisbane time
|
||||
TimeZoneRollback useZone(QByteArray("AEST-10:00"));
|
||||
|
||||
@ -3485,9 +3488,6 @@ void tst_QDateTime::systemTimeZoneChange() const
|
||||
useZone.reset(QByteArray("IST-05:30"));
|
||||
|
||||
QCOMPARE(localDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::LocalTime));
|
||||
#ifdef Q_OS_WINRT
|
||||
QEXPECT_FAIL("", "WinRT gets this wrong, QTBUG-71185", Continue);
|
||||
#endif
|
||||
QVERIFY(localMsecs != localDate.toMSecsSinceEpoch());
|
||||
QCOMPARE(utcDate, QDateTime(QDate(2012, 6, 1), QTime(2, 15, 30), Qt::UTC));
|
||||
QCOMPARE(utcDate.toMSecsSinceEpoch(), utcMsecs);
|
||||
|
@ -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
|
||||
|
||||
SOURCES += tst_qopenglwindow.cpp
|
||||
|
||||
win32:CONFIG+=insignificant_test # QTBUG-46452, QTBUG-49630
|
||||
|
@ -88,7 +88,9 @@ private slots:
|
||||
|
||||
void testToFillPolygons();
|
||||
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
void testNaNandInfinites();
|
||||
#endif
|
||||
|
||||
void closing();
|
||||
|
||||
@ -1228,6 +1230,7 @@ void tst_QPainterPath::testToFillPolygons()
|
||||
QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(signaling_nan)
|
||||
void tst_QPainterPath::testNaNandInfinites()
|
||||
{
|
||||
QPainterPath path1;
|
||||
@ -1271,6 +1274,7 @@ void tst_QPainterPath::testNaNandInfinites()
|
||||
path1.lineTo(QPointF(1, 1));
|
||||
QVERIFY(path1 != path2);
|
||||
}
|
||||
#endif // signaling_nan
|
||||
|
||||
void tst_QPainterPath::connectPathDuplicatePoint()
|
||||
{
|
||||
|
@ -66,6 +66,8 @@ private slots:
|
||||
void defaultFamily();
|
||||
void toAndFromString();
|
||||
void fromStringWithoutStyleName();
|
||||
void fromDegenerateString_data();
|
||||
void fromDegenerateString();
|
||||
|
||||
void sharing();
|
||||
void familyNameWithCommaQuote_data();
|
||||
@ -604,6 +606,25 @@ void tst_QFont::fromStringWithoutStyleName()
|
||||
QCOMPARE(font2.toString(), str);
|
||||
}
|
||||
|
||||
void tst_QFont::fromDegenerateString_data()
|
||||
{
|
||||
QTest::addColumn<QString>("string");
|
||||
|
||||
QTest::newRow("empty") << QString();
|
||||
QTest::newRow("justAComma") << ",";
|
||||
QTest::newRow("commasAndSpaces") << " , , ";
|
||||
QTest::newRow("spaces") << " ";
|
||||
QTest::newRow("spacesTabsAndNewlines") << " \t \n";
|
||||
}
|
||||
|
||||
void tst_QFont::fromDegenerateString()
|
||||
{
|
||||
QFETCH(QString, string);
|
||||
QFont f;
|
||||
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Invalid description.*"));
|
||||
QCOMPARE(f.fromString(string), false);
|
||||
QCOMPARE(f, QFont());
|
||||
}
|
||||
|
||||
void tst_QFont::sharing()
|
||||
{
|
||||
|
@ -2712,13 +2712,8 @@ void tst_QWizard::taskQTBUG_46894_nextButtonShortcut()
|
||||
wizard.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&wizard));
|
||||
|
||||
if (wizard.button(QWizard::NextButton)->text() == "&Next") {
|
||||
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
||||
QKeySequence(Qt::ALT | Qt::Key_Right));
|
||||
} else {
|
||||
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
||||
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
|
||||
}
|
||||
QCOMPARE(wizard.button(QWizard::NextButton)->shortcut(),
|
||||
QKeySequence::mnemonic(wizard.button(QWizard::NextButton)->text()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ void TiledPixmapPainter::paintEvent(QPaintEvent *event)
|
||||
// large pixmap: 2 x 2 tiles
|
||||
// 2x pixmap : 4 x 4 tiles
|
||||
//
|
||||
// On a 2x display the 2x pimxap tiles
|
||||
// On a 2x display the 2x pixmap tiles
|
||||
// will be drawn in high resolution.
|
||||
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X);
|
||||
yoff += tiles * pixmapEdge + 10;
|
||||
|
@ -298,7 +298,7 @@ void Window::init()
|
||||
m_sc = m_r->newSwapChain();
|
||||
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
||||
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||
QSize(), // no need to set the size yet
|
||||
QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
|
||||
1,
|
||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||
releasePool << m_ds;
|
||||
@ -376,16 +376,12 @@ void Window::releaseResources()
|
||||
|
||||
void Window::resizeSwapChain()
|
||||
{
|
||||
const QSize outputSize = m_sc->surfacePixelSize();
|
||||
|
||||
m_ds->setPixelSize(outputSize);
|
||||
m_ds->build(); // == m_ds->release(); m_ds->build();
|
||||
|
||||
m_hasSwapChain = m_sc->buildOrResize();
|
||||
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
|
||||
|
||||
m_elapsedMs = 0;
|
||||
m_elapsedCount = 0;
|
||||
|
||||
const QSize outputSize = m_sc->currentPixelSize();
|
||||
m_proj = m_r->clipSpaceCorrMatrix();
|
||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
||||
m_proj.translate(0, 0, -4);
|
||||
|
@ -200,12 +200,10 @@ void Window::customInit()
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
|
||||
});
|
||||
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
|
||||
for (int i = 0; i < ATTCOUNT; ++i) {
|
||||
QRhiGraphicsPipeline::TargetBlend blend;
|
||||
blends.append(blend);
|
||||
}
|
||||
d.triPs->setTargetBlends(blends);
|
||||
|
||||
QRhiGraphicsPipeline::TargetBlend blends[ATTCOUNT]; // defaults to blending == false
|
||||
d.triPs->setTargetBlends(blends, blends + ATTCOUNT);
|
||||
|
||||
inputLayout.setBindings({
|
||||
{ 5 * sizeof(float) }
|
||||
});
|
||||
|
@ -240,7 +240,7 @@ void Window::customInit()
|
||||
#else
|
||||
d.msaaTriPs->setSampleCount(1);
|
||||
#endif
|
||||
d.msaaTriPs->setShaderStages(d.triPs->shaderStages());
|
||||
d.msaaTriPs->setShaderStages(d.triPs->cbeginShaderStages(), d.triPs->cendShaderStages());
|
||||
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
|
||||
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
|
||||
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);
|
||||
|
@ -400,7 +400,7 @@ void Window::init()
|
||||
{
|
||||
m_sc = r.r->newSwapChain();
|
||||
m_ds = r.r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||
QSize(), // no need to set the size yet
|
||||
QSize(),
|
||||
1,
|
||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||
m_releasePool << m_ds;
|
||||
@ -427,13 +427,9 @@ void Window::releaseResources()
|
||||
|
||||
void Window::resizeSwapChain()
|
||||
{
|
||||
const QSize outputSize = m_sc->surfacePixelSize();
|
||||
|
||||
m_ds->setPixelSize(outputSize);
|
||||
m_ds->build();
|
||||
|
||||
m_hasSwapChain = m_sc->buildOrResize();
|
||||
|
||||
const QSize outputSize = m_sc->currentPixelSize();
|
||||
m_proj = r.r->clipSpaceCorrMatrix();
|
||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
||||
m_proj.translate(0, 0, -4);
|
||||
|
@ -441,7 +441,7 @@ void Renderer::init()
|
||||
{
|
||||
m_sc = r->newSwapChain();
|
||||
m_ds = r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||
QSize(), // no need to set the size yet
|
||||
QSize(),
|
||||
1,
|
||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||
m_releasePool << m_ds;
|
||||
@ -543,11 +543,9 @@ void Renderer::render(bool newlyExposed, bool wakeBeforePresent)
|
||||
|
||||
auto buildOrResizeSwapChain = [this] {
|
||||
qDebug() << "renderer" << this << "build or resize swapchain for window" << window;
|
||||
const QSize outputSize = m_sc->surfacePixelSize();
|
||||
qDebug() << " size is" << outputSize;
|
||||
m_ds->setPixelSize(outputSize);
|
||||
m_ds->build();
|
||||
m_hasSwapChain = m_sc->buildOrResize();
|
||||
const QSize outputSize = m_sc->currentPixelSize();
|
||||
qDebug() << " size is" << outputSize;
|
||||
m_proj = r->clipSpaceCorrMatrix();
|
||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
|
||||
m_proj.translate(0, 0, -4);
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include <QPlatformSurfaceEvent>
|
||||
#include <QElapsedTimer>
|
||||
#include <QTimer>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <QFile>
|
||||
@ -70,7 +71,6 @@
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QLoggingCategory>
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
|
||||
@ -307,7 +307,7 @@ void Window::init()
|
||||
m_sc = m_r->newSwapChain();
|
||||
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
|
||||
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||
QSize(), // no need to set the size yet
|
||||
QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
|
||||
sampleCount,
|
||||
QRhiRenderBuffer::UsedWithSwapChainOnly);
|
||||
m_sc->setWindow(this);
|
||||
@ -344,16 +344,12 @@ void Window::releaseResources()
|
||||
|
||||
void Window::resizeSwapChain()
|
||||
{
|
||||
const QSize outputSize = m_sc->surfacePixelSize();
|
||||
|
||||
m_ds->setPixelSize(outputSize);
|
||||
m_ds->build(); // == m_ds->release(); m_ds->build();
|
||||
|
||||
m_hasSwapChain = m_sc->buildOrResize();
|
||||
m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
|
||||
|
||||
m_frameCount = 0;
|
||||
m_timer.restart();
|
||||
|
||||
const QSize outputSize = m_sc->currentPixelSize();
|
||||
m_proj = m_r->clipSpaceCorrMatrix();
|
||||
m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
|
||||
m_proj.translate(0, 0, -4);
|
||||
@ -444,6 +440,8 @@ int main(int argc, char **argv)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QLoggingCategory::setFilterRules(QLatin1String("qt.rhi.*=true"));
|
||||
|
||||
// Defaults.
|
||||
#if defined(Q_OS_WIN)
|
||||
graphicsApi = D3D11;
|
||||
|
@ -68,6 +68,8 @@ struct {
|
||||
QRhiTexture *newTex = nullptr;
|
||||
QRhiTexture *importedTex = nullptr;
|
||||
int testStage = 0;
|
||||
|
||||
QRhiShaderResourceBinding bindings[2];
|
||||
} d;
|
||||
|
||||
void Window::customInit()
|
||||
@ -100,10 +102,10 @@ void Window::customInit()
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
|
||||
});
|
||||
|
||||
d.bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf);
|
||||
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler);
|
||||
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||
d.srb->build();
|
||||
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
@ -211,9 +213,8 @@ void Window::customRender()
|
||||
u->copyTexture(d.newTex, d.tex, desc);
|
||||
|
||||
// Now replace d.tex with d.newTex as the shader resource.
|
||||
auto bindings = d.srb->bindings();
|
||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||
d.srb->setBindings(bindings);
|
||||
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||
// "rebuild", whatever that means for a given backend. This srb is
|
||||
// already live as the ps in the setGraphicsPipeline references it,
|
||||
// but that's fine. Changes will be picked up automatically.
|
||||
@ -259,9 +260,8 @@ void Window::customRender()
|
||||
// underneath (owned by d.tex)
|
||||
|
||||
// switch to showing d.importedTex
|
||||
auto bindings = d.srb->bindings();
|
||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
|
||||
d.srb->setBindings(bindings);
|
||||
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
|
||||
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||
d.srb->build();
|
||||
} else {
|
||||
qWarning("Accessing native texture object is not supported");
|
||||
@ -270,9 +270,8 @@ void Window::customRender()
|
||||
|
||||
// Exercise uploading uncompressed data without a QImage.
|
||||
if (d.testStage == 7) {
|
||||
auto bindings = d.srb->bindings();
|
||||
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||
d.srb->setBindings(bindings);
|
||||
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
|
||||
d.srb->setBindings(d.bindings, d.bindings + 2);
|
||||
d.srb->build();
|
||||
|
||||
const QSize sz(221, 139);
|
||||
|
@ -94,11 +94,11 @@ void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp)
|
||||
|
||||
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
|
||||
premulAlphaBlend.enable = true;
|
||||
QVector<QRhiGraphicsPipeline::TargetBlend> rtblends;
|
||||
QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> rtblends;
|
||||
for (int i = 0; i < m_colorAttCount; ++i)
|
||||
rtblends << premulAlphaBlend;
|
||||
|
||||
m_ps->setTargetBlends(rtblends);
|
||||
m_ps->setTargetBlends(rtblends.cbegin(), rtblends.cend());
|
||||
m_ps->setSampleCount(m_sampleCount);
|
||||
|
||||
if (m_depthWrite) { // TriangleOnCube may want to exercise this
|
||||
|
Loading…
Reference in New Issue
Block a user