diff options
author | Qt Forward Merge Bot <[email protected]> | 2019-09-28 01:00:51 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <[email protected]> | 2019-09-28 01:01:03 +0200 |
commit | fbda189e081e6c7abf82334c0ac71b16ec2c37dd (patch) | |
tree | 92bdcfeb6c32de9c90ea126714907afa18ef44f1 | |
parent | d12bf4eb8353f33499cbec4e105431668dbe8c88 (diff) | |
parent | e8d7df4cb2586ba5098fb4f476807ba7992d9cea (diff) |
Merge "Merge remote-tracking branch 'origin/5.14' into 5.15"
36 files changed, 515 insertions, 69 deletions
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 } 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 \ 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 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 <private/qlocale_tools_p.h> @@ -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) 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; 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 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(); 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 <QDir> #include <QSaveFile> #include <QLoggingCategory> +#include <QCryptographicHash> #ifdef Q_OS_UNIX #include <sys/mman.h> @@ -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<ShaderDesc> 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 <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> #include <QtCore/qloggingcategory.h> -#include <QtCore/qcryptographichash.h> #include <QtCore/qcoreapplication.h> #include <QtGui/qtransform.h> #include <QtGui/QColor> @@ -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()); 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<T, T *x, T *y, T *w, T *h) { // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in - // Vulkan/Metal/D3D. We also need proper clamping since some - // validation/debug layers are allergic to out of bounds scissor or - // viewport rects. + // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both + // negative x or y, and partly or completely out of bounds rects are + // allowed. The only thing the input here cannot have is a negative width + // or height. We must handle all other input gracefully, clamping to a zero + // width or height rect in the worst case, and ensuring the resulting rect + // is inside the rendertarget's bounds because some APIs' validation/debug + // layers are allergic to out of bounds scissor or viewport rects. const T outputWidth = outputSize.width(); const T outputHeight = outputSize.height(); const T inputWidth = r[2]; const T inputHeight = r[3]; - *x = qMax<T>(0, r[0]); - *y = qMax<T>(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<T>(0, *x, outputWidth - 1); + *y = qBound<T>(0, *y, outputHeight - 1); + *w = qMax<T>(0, inputWidth - widthOffset); + *h = qMax<T>(0, inputHeight - heightOffset); + if (*x + *w > outputWidth) - *w = outputWidth - *x; + *w = qMax<T>(0, outputWidth - *x - 1); if (*y + *h > outputHeight) - *h = outputHeight - *y; + *h = qMax<T>(0, outputHeight - *y - 1); return true; } diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 2d51d892e32..cc5d41ea46b 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<float, 4> 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<int, 4> 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); @@ -2250,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); 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(); 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<uint *>(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); 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 new file mode 100644 index 00000000000..25a7c64c8af --- /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<QRhiResource *> 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(), m_clearColor, { 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 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="cubemap.vert.qsb">../cubemap/cubemap.vert.qsb</file> + <file alias="cubemap.frag.qsb">../cubemap/cubemap.frag.qsb</file> + <file alias="c.png">../cubemap/c.png</file> +</qresource> +</RCC> 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/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 \ 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(); |