From d512f5ac3a53f7d153e9d1de8d3f468273bd7708 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Sun, 8 Sep 2019 13:56:58 +0200 Subject: [PATCH 01/13] Handle returned bitmap glyph when not requested Add back code to handle bitmap glyphs returned when we did not request a bitmap glyph. This is a can happen on some configurations where bitmaps are not suppressed. Fixes: QTBUG-78116 Change-Id: Ie0c6cfbf9c50456431b0e3a23e568f3399e5a879 Reviewed-by: Lars Knoll --- .../fontdatabases/freetype/qfontengine_ft.cpp | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 60119419823..8c6cc8fbc1e 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -1110,16 +1110,32 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, glyph_buffer.reset(new uchar[glyph_buffer_size]); if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { - Q_ASSERT(format == Format_Mono); uchar *src = slot->bitmap.buffer; uchar *dst = glyph_buffer.data(); int h = slot->bitmap.rows; - - int bytes = ((info.width + 7) & ~7) >> 3; - while (h--) { - memcpy (dst, src, bytes); - dst += pitch; - src += slot->bitmap.pitch; + // Some fonts return bitmaps even when we requested something else: + if (format == Format_Mono) { + int bytes = ((info.width + 7) & ~7) >> 3; + while (h--) { + memcpy (dst, src, bytes); + dst += pitch; + src += slot->bitmap.pitch; + } + } else if (format == Format_A8) { + while (h--) { + for (int x = 0; x < int{info.width}; x++) + dst[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00); + dst += pitch; + src += slot->bitmap.pitch; + } + } else { + while (h--) { + uint *dd = reinterpret_cast(dst); + for (int x = 0; x < int{info.width}; x++) + dd[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffffff : 0x00000000); + dst += pitch; + src += slot->bitmap.pitch; + } } } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) { Q_ASSERT(format == Format_ARGB); From 9a1eb86f3d4cd4b0d99f053f9bc9d304289b99f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 25 Sep 2019 12:54:12 +0200 Subject: [PATCH 02/13] macOS: Prevent warnings about object files without any symbols Change-Id: Iafe976bdd27da0476b2e6bb6d84db8ca34aa0a62 Reviewed-by: Alexandru Croitor --- mkspecs/features/mac/no_warn_empty_obj_files.prf | 7 +++++++ mkspecs/features/qt_build_config.prf | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 mkspecs/features/mac/no_warn_empty_obj_files.prf diff --git a/mkspecs/features/mac/no_warn_empty_obj_files.prf b/mkspecs/features/mac/no_warn_empty_obj_files.prf new file mode 100644 index 00000000000..598938ab12c --- /dev/null +++ b/mkspecs/features/mac/no_warn_empty_obj_files.prf @@ -0,0 +1,7 @@ +# Prevent warnings about object files without any symbols. This is a common +# thing in Qt as we tend to build files unconditionally, and then use ifdefs +# to compile out parts that are not relevant. +QMAKE_RANLIB += -no_warning_for_no_symbols + +# We have to tell 'ar' to not run ranlib by itself +QMAKE_AR += -S diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 745b09a8851..8273ba3fe14 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -88,6 +88,9 @@ cross_compile: \ android|uikit|winrt: \ CONFIG += builtin_testdata +# Prevent warnings about object files without any symbols +macos: CONFIG += no_warn_empty_obj_files + CONFIG += \ utf8_source \ create_prl link_prl \ From fc4a6b0b974329202c50ff0b04d5fd0aea53e6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 25 Sep 2019 14:38:08 +0200 Subject: [PATCH 03/13] Fix rpath on UIKit systems Change-Id: I0b35c32f3730dc15d868b10489abeda909bbe926 Reviewed-by: Alexandru Croitor Reviewed-by: Timur Pocheptsov --- mkspecs/features/mac/default_post.prf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf index 993f4d56a95..03084c7f071 100644 --- a/mkspecs/features/mac/default_post.prf +++ b/mkspecs/features/mac/default_post.prf @@ -71,7 +71,8 @@ qt { # Add the same default rpaths as Xcode does for new projects. # This is especially important for iOS/tvOS/watchOS where no other option is possible. !no_default_rpath { - QMAKE_RPATHDIR += @executable_path/../Frameworks + uikit: QMAKE_RPATHDIR += @executable_path/Frameworks + else: QMAKE_RPATHDIR += @executable_path/../Frameworks equals(TEMPLATE, lib):!plugin:lib_bundle: QMAKE_RPATHDIR += @loader_path/Frameworks } From dc042c6deea7e90b4a9dfcffdc33cbe61df421bd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 24 Sep 2019 16:12:22 +0200 Subject: [PATCH 04/13] Windows: QSysInfo::prettyProductName(): Improve version formatting For Windows 10 and higher, the SP version and major/minor versions are not relevant any more; the release id (displayed by the winver tool as "Version" should be displayed instead. Add helpers and change the output accordingly. For Windows 7, output the build number. [ChangeLog][QtCore][Windows] QSysInfo::prettyProductName() now returns a version including the Windows 10 release id or Windows 7 build number respectively, resembling the version string displayed by the winver tool. Change-Id: Ia783272a0da234d2f7ff35c4a9a6fc296da277e0 Reviewed-by: Volker Hilsheimer --- src/corelib/global/qglobal.cpp | 70 +++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index dfd51377039..123aeb1f7ca 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -48,6 +48,10 @@ #include "qoperatingsystemversion_p.h" #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINRT) #include "qoperatingsystemversion_win_p.h" +# if QT_CONFIG(settings) +# include "qsettings.h" +# include "qvariant.h" +# endif #endif #include @@ -2186,12 +2190,36 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion() QT_WARNING_POP #endif +static QString readRegistryString(const QString &key, const QString &subKey) +{ +#if QT_CONFIG(settings) + QSettings settings(key, QSettings::NativeFormat); + return settings.value(subKey).toString(); +#else + Q_UNUSED(key); + Q_UNUSED(subKey); + return QString(); +#endif +} + +static inline QString windowsVersionKey() { return QStringLiteral(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)"); } + +static inline QString windows10ReleaseId() +{ + return readRegistryString(windowsVersionKey(), QStringLiteral("ReleaseId")); +} + +static inline QString windows7Build() +{ + return readRegistryString(windowsVersionKey(), QStringLiteral("CurrentBuild")); +} + static QString winSp_helper() { const auto osv = qWindowsVersionInfo(); const qint16 major = osv.wServicePackMajor; if (major) { - QString sp = QStringLiteral(" SP ") + QString::number(major); + QString sp = QStringLiteral("SP ") + QString::number(major); const qint16 minor = osv.wServicePackMinor; if (minor) sp += QLatin1Char('.') + QString::number(minor); @@ -2904,19 +2932,35 @@ QString QSysInfo::prettyProductName() { #if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) const auto version = QOperatingSystemVersion::current(); + const int majorVersion = version.majorVersion(); + const QString versionString = QString::number(majorVersion) + QLatin1Char('.') + + QString::number(version.minorVersion()); + QString result = version.name() + QLatin1Char(' '); const char *name = osVer_helper(version); - if (name) - return version.name() + QLatin1Char(' ') + QLatin1String(name) -# if defined(Q_OS_WIN) - + winSp_helper() -# endif - + QLatin1String(" (") + QString::number(version.majorVersion()) - + QLatin1Char('.') + QString::number(version.minorVersion()) - + QLatin1Char(')'); - else - return version.name() + QLatin1Char(' ') - + QString::number(version.majorVersion()) + QLatin1Char('.') - + QString::number(version.minorVersion()); + if (!name) + return result + versionString; + result += QLatin1String(name); +# if !defined(Q_OS_WIN) + return result + QLatin1String(" (") + versionString + QLatin1Char(')'); +# else + // (resembling winver.exe): Windows 10 "Windows 10 Version 1809" + result += QLatin1String(" Version "); + if (majorVersion >= 10) { + const auto releaseId = windows10ReleaseId(); + if (!releaseId.isEmpty()) + result += QLatin1String(" Version ") + releaseId; + return result; + } + // Windows 7: "Windows 7 Version 6.1 (Build 7601: Service Pack 1)" + result += versionString + QLatin1String(" ("); + const auto build = windows7Build(); + if (!build.isEmpty()) + result += QLatin1String("Build ") + build; + const auto servicePack = winSp_helper(); + if (!servicePack.isEmpty()) + result += QLatin1String(": ") + servicePack; + return result + QLatin1Char(')'); +# endif // Windows #elif defined(Q_OS_HAIKU) return QLatin1String("Haiku ") + productVersion(); #elif defined(Q_OS_UNIX) From 06a7aba731a8b0a3027d14b7aa37229d1ed46d32 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 25 Sep 2019 16:06:02 +0200 Subject: [PATCH 05/13] Fix QCalendar::isValid(): make it const Spotted in API change review, thanks to Albert Astals Cid. Also added documentation of this method. Change-Id: I2ef2c526a98b571a3cb3bb5f93d1952b1b0d63a9 Reviewed-by: Albert Astals Cid --- src/corelib/time/qcalendar.cpp | 11 ++++++++++- src/corelib/time/qcalendar.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp index d706f1d5ab6..d308aeba2b4 100644 --- a/src/corelib/time/qcalendar.cpp +++ b/src/corelib/time/qcalendar.cpp @@ -701,7 +701,7 @@ const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system) calendar being constructed by other means first. With no argument, the default constructor returns the Gregorian calendar. - \sa QCalendar, System + \sa QCalendar, System, isValid() */ QCalendar::QCalendar() @@ -723,6 +723,15 @@ QCalendar::QCalendar(QLatin1String name) QCalendar::QCalendar(QStringView name) : d(QCalendarBackend::fromName(name)) {} +/* + \fn bool QCalendar::isValid() const + + Returns true if this is a valid calendar object. + + Constructing a calendar with an unrecognised calendar name may result in an + invalid object. Use this method to check after creating a calendar by name. +*/ + // Date queries: /*! diff --git a/src/corelib/time/qcalendar.h b/src/corelib/time/qcalendar.h index dd3df76e171..42c8e150c55 100644 --- a/src/corelib/time/qcalendar.h +++ b/src/corelib/time/qcalendar.h @@ -137,7 +137,7 @@ public: explicit QCalendar(QStringView name); // QCalendar is a trivially copyable value type. - bool isValid() { return d != nullptr; } + bool isValid() const { return d != nullptr; } // Date queries: int daysInMonth(int month, int year = Unspecified) const; From 30e27328e3d6446a343107c96f41324197ed7ef1 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 24 Sep 2019 13:24:08 +0200 Subject: [PATCH 06/13] rhi: Unify handling of special cases for scissor and viewport rects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With OpenGL a scissor (or viewport) rectangle is not allowed to have a negative width or height. Everything else is allowed. This is also the semantic we wish to keep for QRhiViewport and QRhiScissor. This raises some problems. For instance, when we do bottom-left - top-left rectangle conversion, the case of partially out of bounds rects needs to be taken into account. Otherwise, Qt Quick ends up in wrong scissoring in certain cases, typically when the QQuickWindow size is decreased so the content does not fit because that will then start generating negative x, y scissors for clipping (which is perfectly valid but the QRhi backends need to be able to deal with it) Then there is the problem of having to clamp width and height carefully, because some validation layers for some APIs will reject a viewport or scissor with partially out of bounds rectangles. To verify all this, add a new manual test, based on the cubemap one. (cubemap was chosen because that is an ideal test scene as it fills the viewport completely, and so it is visually straightforward when a scissor rectangle is moving around over it) Fixes: QTBUG-78702 Change-Id: I60614836432ea9934fc0dbd0ac7e88931f476542 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 22 +- src/gui/rhi/qrhi_p_p.h | 32 ++- src/gui/rhi/qrhigles2.cpp | 16 +- .../rhi/cubemap_scissor/cubemap_scissor.cpp | 241 ++++++++++++++++++ .../rhi/cubemap_scissor/cubemap_scissor.pro | 8 + .../rhi/cubemap_scissor/cubemap_scissor.qrc | 7 + tests/manual/rhi/rhi.pro | 1 + 7 files changed, 306 insertions(+), 21 deletions(-) create mode 100644 tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp create mode 100644 tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro create mode 100644 tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 858be0159b3..ee4caa47a04 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -707,8 +707,8 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v) Used with QRhiCommandBuffer::setViewport(). - \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are - bottom-left. + QRhi assumes OpenGL-style viewport coordinates, meaning x and y are + bottom-left. Negative width or height are not allowed. Typical usage is like the following: @@ -737,7 +737,9 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v) Constructs a viewport description with the rectangle specified by \a x, \a y, \a w, \a h and the depth range \a minDepth and \a maxDepth. - \note x and y are assumed to be the bottom-left position. + \note \a x and \a y are assumed to be the bottom-left position. \a w and \a + h should not be negative, the viewport will be ignored by + QRhiCommandBuffer::setViewport() otherwise. \sa QRhi::clipSpaceCorrMatrix() */ @@ -810,8 +812,12 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v) only possible with a QRhiGraphicsPipeline that has QRhiGraphicsPipeline::UsesScissor set. - \note QRhi assumes OpenGL-style scissor coordinates, meaning x and y are - bottom-left. + QRhi assumes OpenGL-style scissor coordinates, meaning x and y are + bottom-left. Negative width or height are not allowed. However, apart from + that, the flexible OpenGL semantics apply: negative x and y, partially out + of bounds rectangles, etc. will be handled gracefully, clamping as + appropriate. Therefore, any rendering logic targeting OpenGL can feed + scissor rectangles into QRhiScissor as-is, without any adaptation. \sa QRhiCommandBuffer::setScissor(), QRhiViewport */ @@ -826,7 +832,11 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v) Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and \a h. - \note x and y are assumed to be the bottom-left position. + \note \a x and \a y are assumed to be the bottom-left position. Negative \a w + or \a h are not allowed, such scissor rectangles will be ignored by + QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply: + negative x and y, partially out of bounds rectangles, etc. will be handled + gracefully, clamping as appropriate. */ QRhiScissor::QRhiScissor(int x, int y, int w, int h) : m_rect { { x, y, w, h } } diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 63f27b6de42..be2808549c9 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -233,27 +233,37 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array(0, r[0]); - *y = qMax(0, outputHeight - (r[1] + inputHeight)); - *w = inputWidth; - *h = inputHeight; - - if (*x >= outputWidth || *y >= outputHeight) + if (inputWidth < 0 || inputHeight < 0) return false; + *x = r[0]; + *y = outputHeight - (r[1] + inputHeight); + + const T widthOffset = *x < 0 ? -*x : 0; + const T heightOffset = *y < 0 ? -*y : 0; + + *x = qBound(0, *x, outputWidth - 1); + *y = qBound(0, *y, outputHeight - 1); + *w = qMax(0, inputWidth - widthOffset); + *h = qMax(0, inputHeight - heightOffset); + if (*x + *w > outputWidth) - *w = outputWidth - *x; + *w = qMax(0, outputWidth - *x - 1); if (*y + *h > outputHeight) - *h = outputHeight - *y; + *h = qMax(0, outputHeight - *y - 1); return true; } diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 2d51d892e32..838c28efa20 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1004,8 +1004,12 @@ void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) QGles2CommandBuffer::Command cmd; cmd.cmd = QGles2CommandBuffer::Command::Viewport; const std::array r = viewport.viewport(); - cmd.args.viewport.x = qMax(0.0f, r[0]); - cmd.args.viewport.y = qMax(0.0f, r[1]); + // A negative width or height is an error. A negative x or y is not. + if (r[2] < 0.0f || r[3] < 0.0f) + return; + + cmd.args.viewport.x = r[0]; + cmd.args.viewport.y = r[1]; cmd.args.viewport.w = r[2]; cmd.args.viewport.h = r[3]; cmd.args.viewport.d0 = viewport.minDepth(); @@ -1021,8 +1025,12 @@ void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) QGles2CommandBuffer::Command cmd; cmd.cmd = QGles2CommandBuffer::Command::Scissor; const std::array r = scissor.scissor(); - cmd.args.scissor.x = qMax(0, r[0]); - cmd.args.scissor.y = qMax(0, r[1]); + // A negative width or height is an error. A negative x or y is not. + if (r[2] < 0 || r[3] < 0) + return; + + cmd.args.scissor.x = r[0]; + cmd.args.scissor.y = r[1]; cmd.args.scissor.w = r[2]; cmd.args.scissor.h = r[3]; cbD->commands.append(cmd); diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp new file mode 100644 index 00000000000..4281c787932 --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is a test for scissoring. Based on the cubemap test (because there the +// rendering covers the entire viewport which is what we need here). The +// scissor rectangle moves first up, then down, then from the center to the +// left and then to right. The important part is to ensure that the behavior +// identical between all backends, especially when the rectangle is partly or +// fully off window. + +#include "../shared/examplefw.h" +#include "../shared/cube.h" + +struct { + QVector releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + + QPoint scissorBottomLeft; + QSize scissorSize; + int scissorAnimState = 0; + QSize outputSize; +} d; + +void Window::customInit() +{ + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); + d.ubuf->build(); + d.releasePool << d.ubuf; + + const QSize cubeMapSize(512, 512); + d.tex = m_r->newTexture(QRhiTexture::RGBA8, cubeMapSize, 1, QRhiTexture::CubeMap); + d.releasePool << d.tex; + d.tex->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, cube); + + QImage img = QImage(":/c.png").mirrored().convertToFormat(QImage::Format_RGBA8888); + // just use the same image for all faces for now + QRhiTextureSubresourceUploadDescription subresDesc(img); + QRhiTextureUploadDescription desc({ + { 0, 0, subresDesc }, // +X + { 1, 0, subresDesc }, // -X + { 2, 0, subresDesc }, // +Y + { 3, 0, subresDesc }, // -Y + { 4, 0, subresDesc }, // +Z + { 5, 0, subresDesc } // -Z + }); + d.initialUpdates->uploadTexture(d.tex, desc); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::Repeat, QRhiSampler::Repeat); + d.releasePool << d.sampler; + d.sampler->build(); + + 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.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + + d.ps->setFlags(QRhiGraphicsPipeline::UsesScissor); + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual); + + d.ps->setCullMode(QRhiGraphicsPipeline::Front); // we are inside the cube so cull front, not back + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); // front is ccw in the cube data + + QShader vs = getShader(QLatin1String(":/cubemap.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/cubemap.frag.qsb")); + Q_ASSERT(fs.isValid()); + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); + + d.scissorAnimState = 0; +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +static void advanceScissor() +{ + switch (d.scissorAnimState) { + case 1: // up + d.scissorBottomLeft.setX(d.outputSize.width() / 4); + d.scissorBottomLeft.ry() += 1; + if (d.scissorBottomLeft.y() > d.outputSize.height() + 100) + d.scissorAnimState = 2; + break; + case 2: // down + d.scissorBottomLeft.ry() -= 1; + if (d.scissorBottomLeft.y() < -d.scissorSize.height() - 100) + d.scissorAnimState = 3; + break; + case 3: // left + d.scissorBottomLeft.setY(d.outputSize.height() / 4); + d.scissorBottomLeft.rx() += 1; + if (d.scissorBottomLeft.x() > d.outputSize.width() + 100) + d.scissorAnimState = 4; + break; + case 4: // right + d.scissorBottomLeft.rx() -= 1; + if (d.scissorBottomLeft.x() < -d.scissorSize.width() - 100) + d.scissorAnimState = 1; + break; + } + + qDebug() << "scissor bottom-left" << d.scissorBottomLeft << "size" << d.scissorSize; +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + d.outputSize = outputSizeInPixels; + if (d.scissorAnimState == 0) { + d.scissorBottomLeft = QPoint(outputSizeInPixels.width() / 4, 0); + d.scissorSize = QSize(outputSizeInPixels.width() / 2, outputSizeInPixels.height() / 2); + d.scissorAnimState = 1; + } + + QMatrix4x4 mvp = m_r->clipSpaceCorrMatrix(); + mvp.perspective(90.0f, outputSizeInPixels.width() / (float) outputSizeInPixels.height(), 0.01f, 1000.0f); + // cube vertices go from -1..1 + mvp.scale(10); + static float rx = 0; + mvp.rotate(rx, 1, 0, 0); + rx += 0.5f; + // no translation + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + + // Apply a scissor rectangle that moves around on the screen, also + // exercising the out of screen (negative x or y) case. + cb->setScissor(QRhiScissor(d.scissorBottomLeft.x(), d.scissorBottomLeft.y(), + d.scissorSize.width(), d.scissorSize.height())); + + cb->setShaderResources(); + + const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(36); + cb->endPass(); + + advanceScissor(); +} diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro new file mode 100644 index 00000000000..1f02bda87ab --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + cubemap_scissor.cpp + +RESOURCES = cubemap_scissor.qrc diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc new file mode 100644 index 00000000000..8a0ae17dc86 --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc @@ -0,0 +1,7 @@ + + + ../cubemap/cubemap.vert.qsb + ../cubemap/cubemap.frag.qsb + ../cubemap/c.png + + diff --git a/tests/manual/rhi/rhi.pro b/tests/manual/rhi/rhi.pro index d3661ff169d..4768ee1c6da 100644 --- a/tests/manual/rhi/rhi.pro +++ b/tests/manual/rhi/rhi.pro @@ -8,6 +8,7 @@ SUBDIRS += \ msaatexture \ msaarenderbuffer \ cubemap \ + cubemap_scissor \ multiwindow \ multiwindow_threaded \ triquadcube \ From 22d22eb2824fb06f69f87bda27b1cfdf45efbc1f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 26 Sep 2019 09:37:49 +0200 Subject: [PATCH 07/13] rhi: Add a --transparent option to manual tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will also cause clearing to 0,0,0,0. Essential in order to allow fast testing of window transparency issues in combination with QRhi and the various backends. Change-Id: Iee2763c1d06f1d3e5d59a9142abaf30fab1dc543 Reviewed-by: Christian Strømme --- .../compressedtexture_bc1.cpp | 2 +- .../compressedtexture_bc1_subupload.cpp | 2 +- tests/manual/rhi/computebuffer/computebuffer.cpp | 2 +- tests/manual/rhi/computeimage/computeimage.cpp | 2 +- tests/manual/rhi/cubemap/cubemap.cpp | 2 +- .../rhi/cubemap_scissor/cubemap_scissor.cpp | 2 +- tests/manual/rhi/floattexture/floattexture.cpp | 2 +- tests/manual/rhi/instancing/instancing.cpp | 2 +- tests/manual/rhi/mrt/mrt.cpp | 2 +- .../rhi/msaarenderbuffer/msaarenderbuffer.cpp | 2 +- tests/manual/rhi/msaatexture/msaatexture.cpp | 2 +- tests/manual/rhi/shadowmap/shadowmap.cpp | 2 +- tests/manual/rhi/shared/examplefw.h | 16 ++++++++++++++++ tests/manual/rhi/texuploads/texuploads.cpp | 2 +- tests/manual/rhi/triquadcube/triquadcube.cpp | 2 +- 15 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp index 27dd8097ade..bb3722bec55 100644 --- a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp +++ b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp @@ -182,7 +182,7 @@ void Window::customRender() QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); diff --git a/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp index 87d1e7646a0..4931c8eaa1a 100644 --- a/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp +++ b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp @@ -197,7 +197,7 @@ void Window::customRender() QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); diff --git a/tests/manual/rhi/computebuffer/computebuffer.cpp b/tests/manual/rhi/computebuffer/computebuffer.cpp index 2a3e0b92b5a..c991a114382 100644 --- a/tests/manual/rhi/computebuffer/computebuffer.cpp +++ b/tests/manual/rhi/computebuffer/computebuffer.cpp @@ -195,7 +195,7 @@ void Window::customRender() cb->endComputePass(); // graphics pass - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); cb->setGraphicsPipeline(d.graphicsPipeline); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); QRhiCommandBuffer::VertexInput vbufBinding(d.sbuf, 0); diff --git a/tests/manual/rhi/computeimage/computeimage.cpp b/tests/manual/rhi/computeimage/computeimage.cpp index 51bf216c5ab..a6c860f8eee 100644 --- a/tests/manual/rhi/computeimage/computeimage.cpp +++ b/tests/manual/rhi/computeimage/computeimage.cpp @@ -217,7 +217,7 @@ void Window::customRender() cb->dispatch(d.imageSize.width() / 16, d.imageSize.height() / 16, 1); cb->endComputePass(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); cb->setShaderResources(); diff --git a/tests/manual/rhi/cubemap/cubemap.cpp b/tests/manual/rhi/cubemap/cubemap.cpp index df302736a22..fe6ac9762ec 100644 --- a/tests/manual/rhi/cubemap/cubemap.cpp +++ b/tests/manual/rhi/cubemap/cubemap.cpp @@ -168,7 +168,7 @@ void Window::customRender() // no translation u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); cb->setShaderResources(); diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp index 4281c787932..25a7c64c8af 100644 --- a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp @@ -221,7 +221,7 @@ void Window::customRender() // no translation u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); diff --git a/tests/manual/rhi/floattexture/floattexture.cpp b/tests/manual/rhi/floattexture/floattexture.cpp index 16e58ff00ff..0d24860c780 100644 --- a/tests/manual/rhi/floattexture/floattexture.cpp +++ b/tests/manual/rhi/floattexture/floattexture.cpp @@ -317,7 +317,7 @@ void Window::customRender() } const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); cb->setShaderResources(); diff --git a/tests/manual/rhi/instancing/instancing.cpp b/tests/manual/rhi/instancing/instancing.cpp index 87029e541c6..bdafbd81bc6 100644 --- a/tests/manual/rhi/instancing/instancing.cpp +++ b/tests/manual/rhi/instancing/instancing.cpp @@ -161,7 +161,7 @@ void Window::customRender() u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); } - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); cb->setShaderResources(); diff --git a/tests/manual/rhi/mrt/mrt.cpp b/tests/manual/rhi/mrt/mrt.cpp index b80af7ac879..258871f9b3b 100644 --- a/tests/manual/rhi/mrt/mrt.cpp +++ b/tests/manual/rhi/mrt/mrt.cpp @@ -283,7 +283,7 @@ void Window::customRender() } const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); vbufBinding.second = 0; diff --git a/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp index b77a27b1b57..27dabb2276e 100644 --- a/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp +++ b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp @@ -248,7 +248,7 @@ void Window::customRender() // onscreen (quad) const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); cb->setShaderResources(); diff --git a/tests/manual/rhi/msaatexture/msaatexture.cpp b/tests/manual/rhi/msaatexture/msaatexture.cpp index 46a9b2830c8..d23a4a8d475 100644 --- a/tests/manual/rhi/msaatexture/msaatexture.cpp +++ b/tests/manual/rhi/msaatexture/msaatexture.cpp @@ -315,7 +315,7 @@ void Window::customRender() // onscreen const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); cb->setGraphicsPipeline(d.psLeft); // showing the non-msaa version cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); cb->setShaderResources(); diff --git a/tests/manual/rhi/shadowmap/shadowmap.cpp b/tests/manual/rhi/shadowmap/shadowmap.cpp index 9146be5cc98..424a8b3783f 100644 --- a/tests/manual/rhi/shadowmap/shadowmap.cpp +++ b/tests/manual/rhi/shadowmap/shadowmap.cpp @@ -296,7 +296,7 @@ void Window::customRender() cb->endPass(); // main pass - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); enqueueScene(cb, d.srb, oneRoundedUniformBlockSize, 0); diff --git a/tests/manual/rhi/shared/examplefw.h b/tests/manual/rhi/shared/examplefw.h index 4bd087473bf..220c3d0ff2c 100644 --- a/tests/manual/rhi/shared/examplefw.h +++ b/tests/manual/rhi/shared/examplefw.h @@ -127,6 +127,7 @@ QRhiSwapChain::Flags scFlags = 0; QRhi::BeginFrameFlags beginFrameFlags = 0; QRhi::EndFrameFlags endFrameFlags = 0; int framesUntilTdr = -1; +bool transparentBackground = false; class Window : public QWindow { @@ -167,6 +168,8 @@ protected: QOffscreenSurface *m_fallbackSurface = nullptr; #endif + QColor m_clearColor; + friend int main(int, char**); }; @@ -194,6 +197,8 @@ Window::Window() default: break; } + + m_clearColor = transparentBackground ? Qt::transparent : QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f); } Window::~Window() @@ -477,6 +482,9 @@ int main(int argc, char **argv) QCommandLineOption swOption(QLatin1String("software"), QLatin1String("Prefer a software renderer when choosing the adapter. " "Only applicable with some APIs and platforms.")); cmdLineParser.addOption(swOption); + // Allow testing having a semi-transparent window. + QCommandLineOption transparentOption(QLatin1String("transparent"), QLatin1String("Make background transparent")); + cmdLineParser.addOption(transparentOption); cmdLineParser.process(app); if (cmdLineParser.isSet(nullOption)) @@ -493,6 +501,11 @@ int main(int argc, char **argv) qDebug("Selected graphics API is %s", qPrintable(graphicsApiName())); qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText())); + if (cmdLineParser.isSet(transparentOption)) { + transparentBackground = true; + scFlags |= QRhiSwapChain::SurfaceHasPreMulAlpha; + } + #ifdef EXAMPLEFW_PREINIT void preInit(); preInit(); @@ -508,6 +521,9 @@ int main(int argc, char **argv) fmt.setSwapInterval(0); if (scFlags.testFlag(QRhiSwapChain::sRGB)) fmt.setColorSpace(QSurfaceFormat::sRGBColorSpace); + // Exception: The alpha size is not necessarily OpenGL specific. + if (transparentBackground) + fmt.setAlphaBufferSize(8); QSurfaceFormat::setDefaultFormat(fmt); // Vulkan setup. diff --git a/tests/manual/rhi/texuploads/texuploads.cpp b/tests/manual/rhi/texuploads/texuploads.cpp index dc20ffb1fcf..f29a9891872 100644 --- a/tests/manual/rhi/texuploads/texuploads.cpp +++ b/tests/manual/rhi/texuploads/texuploads.cpp @@ -296,7 +296,7 @@ void Window::customRender() QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); const QSize outputSizeInPixels = m_sc->currentPixelSize(); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->setGraphicsPipeline(d.ps); cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); diff --git a/tests/manual/rhi/triquadcube/triquadcube.cpp b/tests/manual/rhi/triquadcube/triquadcube.cpp index 76dbe558abb..252ec63e21a 100644 --- a/tests/manual/rhi/triquadcube/triquadcube.cpp +++ b/tests/manual/rhi/triquadcube/triquadcube.cpp @@ -230,7 +230,7 @@ void Window::customRender() if (!d.onScreenOnly) d.liveTexCubeRenderer.queueResourceUpdates(u); - cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); cb->debugMarkBegin(QByteArrayLiteral("Triangle")); d.triRenderer.queueDraw(cb, outputSize); cb->debugMarkEnd(); From c06627a230ea758c64ac70a9962a69c843fd0e08 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 25 Sep 2019 15:14:05 +0200 Subject: [PATCH 08/13] rhi: metal: Eliminate redundant setCullMode and setFrontFaceWinding calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-78605 Change-Id: Icc3a9636055b5f45418da28cc05aa02e19370c02 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhimetal.mm | 15 +++++++++++++-- src/gui/rhi/qrhimetal_p_p.h | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index bfd6944cdb6..d4043f00a5f 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -838,8 +838,15 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline [cbD->d->currentRenderPassEncoder setRenderPipelineState: psD->d->ps]; [cbD->d->currentRenderPassEncoder setDepthStencilState: psD->d->ds]; - [cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode]; - [cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding]; + + if (cbD->currentCullMode == -1 || psD->d->cullMode != uint(cbD->currentCullMode)) { + [cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode]; + cbD->currentCullMode = int(psD->d->cullMode); + } + if (cbD->currentFrontFaceWinding == -1 || psD->d->winding != uint(cbD->currentFrontFaceWinding)) { + [cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding]; + cbD->currentFrontFaceWinding = int(psD->d->winding); + } } psD->lastActiveFrameSlot = currentFrameSlot; @@ -3450,6 +3457,10 @@ void QMetalCommandBuffer::resetPerPassCachedState() currentSrbGeneration = 0; currentResSlot = -1; currentIndexBuffer = nullptr; + currentIndexOffset = 0; + currentIndexFormat = QRhiCommandBuffer::IndexUInt16; + currentCullMode = -1; + currentFrontFaceWinding = -1; d->currentFirstVertexBinding = -1; d->currentVertexInputsBuffers.clear(); diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index a08f56072a0..7fd7aba923e 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -271,8 +271,11 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer ComputePass }; + // per-pass (render or compute command encoder) persistent state PassType recordingPass; QRhiRenderTarget *currentTarget; + + // per-pass (render or compute command encoder) volatile (cached) state QRhiGraphicsPipeline *currentGraphicsPipeline; QRhiComputePipeline *currentComputePipeline; uint currentPipelineGeneration; @@ -283,6 +286,8 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer QRhiBuffer *currentIndexBuffer; quint32 currentIndexOffset; QRhiCommandBuffer::IndexFormat currentIndexFormat; + int currentCullMode; + int currentFrontFaceWinding; const QRhiNativeHandles *nativeHandles(); void resetState(); From 0628932fef349d217c0a50a192e7ee6a955994b7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 26 Sep 2019 11:26:51 +0200 Subject: [PATCH 09/13] Move cache key calculation to QOpenGLProgramBinaryCache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This class will likely be used by the OpenGL backend of QRhi as well. Therefore, we need to make it more self-contained and independent. Change-Id: If046ed41e25c70cc9abb45219b451f9179feaa1c Reviewed-by: Christian Strømme --- src/gui/opengl/qopenglprogrambinarycache.cpp | 10 ++++++++++ src/gui/opengl/qopenglprogrambinarycache_p.h | 1 + src/gui/opengl/qopenglshaderprogram.cpp | 7 +------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp index 54160e1240e..14954714572 100644 --- a/src/gui/opengl/qopenglprogrambinarycache.cpp +++ b/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #ifdef Q_OS_UNIX #include @@ -94,6 +95,15 @@ GLEnvInfo::GLEnvInfo() glversion = QByteArray(version); } +QByteArray QOpenGLProgramBinaryCache::ProgramDesc::cacheKey() const +{ + QCryptographicHash keyBuilder(QCryptographicHash::Sha1); + for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : shaders) + keyBuilder.addData(shader.source); + + return keyBuilder.result().toHex(); +} + static inline bool qt_ensureWritableDir(const QString &name) { QDir::root().mkpath(name); diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h index e181a6ab814..fb01e61872b 100644 --- a/src/gui/opengl/qopenglprogrambinarycache_p.h +++ b/src/gui/opengl/qopenglprogrambinarycache_p.h @@ -71,6 +71,7 @@ public: }; struct ProgramDesc { QVector shaders; + QByteArray cacheKey() const; }; QOpenGLProgramBinaryCache(); diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 3c7bd4f90d3..153a5dd9ee5 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -3819,11 +3818,7 @@ bool QOpenGLShaderProgramPrivate::linkBinary() Q_Q(QOpenGLShaderProgram); - QCryptographicHash keyBuilder(QCryptographicHash::Sha1); - for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) - keyBuilder.addData(shader.source); - - const QByteArray cacheKey = keyBuilder.result().toHex(); + const QByteArray cacheKey = binaryProgram.cacheKey(); if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg)) qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s", binaryProgram.shaders.count(), cacheKey.constData()); From fc8d6d3ea142df74885e5d64bc89e677d9f393b6 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 26 Sep 2019 09:38:56 +0200 Subject: [PATCH 10/13] rhi: gl: Fix not resetting color write bits when switching pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was visible in the triquadcube test when enabling transparent window background: the cube on the left was rendered incorrectly because alpha was not written out due to not setting glColorMask() back to the defaults when switching to another pipeline. Change-Id: I7a8c94072e0b68a58fffcc8c1a200e3940dcad44 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhigles2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 838c28efa20..cc5d41ea46b 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2258,6 +2258,7 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps) } } else { f->glDisable(GL_BLEND); + f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } if (psD->m_depthTest) f->glEnable(GL_DEPTH_TEST); From 72457ed0764188264ffdadaf75c4a86f98eeba19 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 25 Sep 2019 16:13:02 +0200 Subject: [PATCH 11/13] Fix doc of QDateTime::YearRange; include its \since 5.14 Change-Id: I2e6c27953ecce95df3ac4868a6d953596ba115f2 Reviewed-by: Thiago Macieira --- src/corelib/time/qdatetime.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 13a54c1210b..6ed0efe77d4 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -3548,6 +3548,7 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT */ /*! + \since 5.14 \enum QDateTime::YearRange This enumerated type describes the range of years (in the Gregorian From 25430f90e6985652be65dec156f010c6d446631f Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 25 Sep 2019 15:56:53 +0200 Subject: [PATCH 12/13] Fix documentation of qfloat16 Various methods were undocumented and even one that was lacked a \since 5.14 Change-Id: I1e65ed1bb9c5b9de06210d7e18af36539aafc4ec Reviewed-by: Thiago Macieira --- src/corelib/global/qfloat16.cpp | 47 ++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index ff2997b73a3..2ba4c79374b 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -107,10 +107,51 @@ QT_BEGIN_NAMESPACE */ /*! - \internal - Implements qFpClassify() for qfloat16. - */ + \internal + \since 5.14 + bool qfloat16::isInf() const noexcept + Tests whether this \c qfloat16 value is an infinity. + + \sa qIsInf() +*/ + +/*! + \internal + \since 5.14 + bool qfloat16::isNaN() const noexcept + + Tests whether this \c qfloat16 value is "not a number". + + \sa qIsNaN() +*/ + +/*! + \since 5.14 + bool qfloat16::isNormal() const noexcept + + Tests whether this \c qfloat16 value is finite and in normal form. + + \sa qFpClassify() +*/ + +/*! + \internal + \since 5.14 + bool qfloat16::isFinite() const noexcept + + Tests whether this \c qfloat16 value is finite. + + \sa qIsFinite() +*/ + +/*! + \internal + \since 5.14 + Implements qFpClassify() for qfloat16. + + \sa qFpClassify() +*/ int qfloat16::fpClassify() const noexcept { return isInf() ? FP_INFINITE : isNaN() ? FP_NAN From 388d539865c4e7f904b29c6e19e41852f24981b8 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 26 Sep 2019 17:11:19 +0300 Subject: [PATCH 13/13] doc: Fix variable name in QDBusArgument snippet Change-Id: I751802d3f9f389e80cbb9aabcdb637d4742d3832 Reviewed-by: Thiago Macieira --- src/dbus/doc/snippets/code/src_qdbus_qdbusargument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbus/doc/snippets/code/src_qdbus_qdbusargument.cpp b/src/dbus/doc/snippets/code/src_qdbus_qdbusargument.cpp index be722201539..b64ea5cf218 100644 --- a/src/dbus/doc/snippets/code/src_qdbus_qdbusargument.cpp +++ b/src/dbus/doc/snippets/code/src_qdbus_qdbusargument.cpp @@ -186,7 +186,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, MyDictionary &myd argument.beginMap(); mydict.clear(); - while ( !argMap.atEnd() ) { + while ( !argument.atEnd() ) { int key; MyValue value; argument.beginMapEntry();