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

This commit is contained in:
Qt Forward Merge Bot 2019-09-28 01:00:51 +02:00
commit fbda189e08
36 changed files with 515 additions and 69 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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)

View File

@ -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:
/*!

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -71,6 +71,7 @@ public:
};
struct ProgramDesc {
QVector<ShaderDesc> shaders;
QByteArray cacheKey() const;
};
QOpenGLProgramBinaryCache();

View File

@ -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());

View File

@ -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 } }

View File

@ -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;
}

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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()) });

View File

@ -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()) });

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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();
}

View File

@ -0,0 +1,8 @@
TEMPLATE = app
QT += gui-private
SOURCES = \
cubemap_scissor.cpp
RESOURCES = cubemap_scissor.qrc

View File

@ -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>

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -8,6 +8,7 @@ SUBDIRS += \
msaatexture \
msaarenderbuffer \
cubemap \
cubemap_scissor \
multiwindow \
multiwindow_threaded \
triquadcube \

View File

@ -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);

View File

@ -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.

View File

@ -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()) });

View File

@ -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();