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

This commit is contained in:
Qt Forward Merge Bot 2020-03-27 01:00:18 +01:00 committed by Edward Welbourne
commit fd44fb7675
7 changed files with 217 additions and 72 deletions

View File

@ -845,7 +845,7 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context,
stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr); stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr);
// Set the viewport // Set the viewport
stateManager->setSimpleViewport(mWidth, mHeight); stateManager->setSimpleViewport(width, height);
// Apply textures // Apply textures
stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler); stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler);

View File

@ -0,0 +1,27 @@
From 029d42d1049dcde7950c11fb9adf07c07a8c4c02 Mon Sep 17 00:00:00 2001
From: Oliver Wolff <oliver.wolff@qt.io>
Date: Wed, 18 Mar 2020 10:56:53 +0100
Subject: [PATCH] ANGLE: Fix resizing of windows (Take 2)
Task-number: QTBUG-62475
Change-Id: I0ea17e7875906508941ae64bb396a4236928b0f9
---
.../angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index e8f13b388f..9ece77ecbc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -845,7 +845,7 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context,
stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr);
// Set the viewport
- stateManager->setSimpleViewport(mWidth, mHeight);
+ stateManager->setSimpleViewport(width, height);
// Apply textures
stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler);
--
2.20.1.windows.1

View File

@ -844,11 +844,6 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
return QCborValue::Tag; return QCborValue::Tag;
} }
#if QT_CONFIG(cborstreamreader)
// in qcborstream.cpp
extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
#endif
#if QT_CONFIG(cborstreamwriter) #if QT_CONFIG(cborstreamwriter)
static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt) static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
{ {
@ -1462,23 +1457,59 @@ static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
return e; return e;
} }
static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader) static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{ {
auto d = new QCborContainerPrivate; if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
return nullptr;
}
QCborContainerPrivate *d = nullptr;
int mapShift = reader.isMap() ? 1 : 0;
if (reader.isLengthKnown()) {
quint64 len = reader.length();
// Clamp allocation to 1M elements (avoids crashing due to corrupt
// stream or loss of precision when converting from quint64 to
// QVector::size_type).
len = qMin(len, quint64(1024 * 1024 - 1));
if (len) {
d = new QCborContainerPrivate;
d->ref.storeRelaxed(1); d->ref.storeRelaxed(1);
d->decodeFromCbor(reader); d->elements.reserve(qsizetype(len) << mapShift);
}
} else {
d = new QCborContainerPrivate;
d->ref.storeRelaxed(1);
}
reader.enterContainer();
if (reader.lastError() != QCborError::NoError)
return d;
while (reader.hasNext() && reader.lastError() == QCborError::NoError)
d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
if (reader.lastError() == QCborError::NoError)
reader.leaveContainer();
return d; return d;
} }
static QCborValue taggedValueFromCbor(QCborStreamReader &reader) static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{ {
if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
return QCborValue::Invalid;
}
auto d = new QCborContainerPrivate; auto d = new QCborContainerPrivate;
d->append(reader.toTag()); d->append(reader.toTag());
reader.next(); reader.next();
if (reader.lastError() == QCborError::NoError) { if (reader.lastError() == QCborError::NoError) {
// decode tagged value // decode tagged value
d->decodeValueFromCbor(reader); d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
} }
QCborValue::Type type; QCborValue::Type type;
@ -1494,6 +1525,13 @@ static QCborValue taggedValueFromCbor(QCborStreamReader &reader)
return QCborContainerPrivate::makeValue(type, -1, d); return QCborContainerPrivate::makeValue(type, -1, d);
} }
// in qcborstream.cpp
extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
{
qt_cbor_stream_set_error(reader.d.data(), error);
}
void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
{ {
auto addByteData_local = [this](QByteArray::size_type len) -> qint64 { auto addByteData_local = [this](QByteArray::size_type len) -> qint64 {
@ -1538,7 +1576,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
return; // error return; // error
if (len != rawlen) { if (len != rawlen) {
// truncation // truncation
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); setErrorInReader(reader, { QCborError::DataTooLarge });
return; return;
} }
@ -1548,7 +1586,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
e.value = addByteData_local(len); e.value = addByteData_local(len);
if (e.value < 0) { if (e.value < 0) {
// overflow // overflow
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); setErrorInReader(reader, { QCborError::DataTooLarge });
return; return;
} }
} }
@ -1562,7 +1600,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
auto utf8result = QUtf8::isValidUtf8(dataPtr() + data.size() - len, len); auto utf8result = QUtf8::isValidUtf8(dataPtr() + data.size() - len, len);
if (!utf8result.isValidUtf8) { if (!utf8result.isValidUtf8) {
r.status = QCborStreamReader::Error; r.status = QCborStreamReader::Error;
qt_cbor_stream_set_error(reader.d.data(), { QCborError::InvalidUtf8String }); setErrorInReader(reader, { QCborError::InvalidUtf8String });
break; break;
} }
isAscii = isAscii && utf8result.isValidAscii; isAscii = isAscii && utf8result.isValidAscii;
@ -1586,7 +1624,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// error // error
r.status = QCborStreamReader::Error; r.status = QCborStreamReader::Error;
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); setErrorInReader(reader, { QCborError::DataTooLarge });
} }
if (r.status == QCborStreamReader::Error) { if (r.status == QCborStreamReader::Error) {
@ -1612,9 +1650,10 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
elements.append(e); elements.append(e);
} }
void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader) void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{ {
switch (reader.type()) { QCborStreamReader::Type t = reader.type();
switch (t) {
case QCborStreamReader::UnsignedInteger: case QCborStreamReader::UnsignedInteger:
case QCborStreamReader::NegativeInteger: case QCborStreamReader::NegativeInteger:
case QCborStreamReader::SimpleType: case QCborStreamReader::SimpleType:
@ -1631,37 +1670,17 @@ void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader)
case QCborStreamReader::Array: case QCborStreamReader::Array:
case QCborStreamReader::Map: case QCborStreamReader::Map:
return append(makeValue(t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, -1,
createContainerFromCbor(reader, remainingRecursionDepth),
MoveContainer));
case QCborStreamReader::Tag: case QCborStreamReader::Tag:
return append(QCborValue::fromCbor(reader)); return append(taggedValueFromCbor(reader, remainingRecursionDepth));
case QCborStreamReader::Invalid: case QCborStreamReader::Invalid:
return; // probably a decode error return; // probably a decode error
} }
} }
void QCborContainerPrivate::decodeFromCbor(QCborStreamReader &reader)
{
int mapShift = reader.isMap() ? 1 : 0;
if (reader.isLengthKnown()) {
quint64 len = reader.length();
// Clamp allocation to 1M elements (avoids crashing due to corrupt
// stream or loss of precision when converting from quint64 to
// QVector::size_type).
len = qMin(len, quint64(1024 * 1024 - 1));
elements.reserve(qsizetype(len) << mapShift);
}
reader.enterContainer();
if (reader.lastError() != QCborError::NoError)
return;
while (reader.hasNext() && reader.lastError() == QCborError::NoError)
decodeValueFromCbor(reader);
if (reader.lastError() == QCborError::NoError)
reader.leaveContainer();
}
#endif // QT_CONFIG(cborstreamreader) #endif // QT_CONFIG(cborstreamreader)
/*! /*!
@ -2363,6 +2382,8 @@ QCborValueRef QCborValue::operator[](qint64 key)
} }
#if QT_CONFIG(cborstreamreader) #if QT_CONFIG(cborstreamreader)
enum { MaximumRecursionDepth = 1024 };
/*! /*!
Decodes one item from the CBOR stream found in \a reader and returns the Decodes one item from the CBOR stream found in \a reader and returns the
equivalent representation. This function is recursive: if the item is a map equivalent representation. This function is recursive: if the item is a map
@ -2423,12 +2444,12 @@ QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
case QCborStreamReader::Map: case QCborStreamReader::Map:
result.n = -1; result.n = -1;
result.t = reader.isArray() ? Array : Map; result.t = reader.isArray() ? Array : Map;
result.container = createContainerFromCbor(reader); result.container = createContainerFromCbor(reader, MaximumRecursionDepth);
break; break;
// tag // tag
case QCborStreamReader::Tag: case QCborStreamReader::Tag:
result = taggedValueFromCbor(reader); result = taggedValueFromCbor(reader, MaximumRecursionDepth);
break; break;
} }

View File

@ -405,9 +405,9 @@ public:
elements.remove(idx); elements.remove(idx);
} }
void decodeValueFromCbor(QCborStreamReader &reader); void decodeValueFromCbor(QCborStreamReader &reader, int remainiingStackDepth);
void decodeFromCbor(QCborStreamReader &reader);
void decodeStringFromCbor(QCborStreamReader &reader); void decodeStringFromCbor(QCborStreamReader &reader);
static inline void setErrorInReader(QCborStreamReader &reader, QCborError error);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -47,6 +47,8 @@
#include <QScopedPointer> #include <QScopedPointer>
#include "qiosurfacegraphicsbuffer.h" #include "qiosurfacegraphicsbuffer.h"
#include <unordered_map>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QCocoaBackingStore : public QRasterBackingStore class QCocoaBackingStore : public QRasterBackingStore
@ -71,8 +73,9 @@ private:
void redrawRoundedBottomCorners(CGRect) const; void redrawRoundedBottomCorners(CGRect) const;
}; };
class QCALayerBackingStore : public QCocoaBackingStore class QCALayerBackingStore : public QObject, public QCocoaBackingStore
{ {
Q_OBJECT
public: public:
QCALayerBackingStore(QWindow *window); QCALayerBackingStore(QWindow *window);
~QCALayerBackingStore(); ~QCALayerBackingStore();
@ -119,6 +122,11 @@ private:
QMacNotificationObserver m_backingPropertiesObserver; QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers; std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
void flushSubWindow(QWindow *window);
std::unordered_map<QWindow*, std::unique_ptr<QCALayerBackingStore>> m_subWindowBackingstores;
void windowDestroyed(QObject *object);
bool m_clearSurfaceOnPaint = true;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -382,7 +382,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// Although undocumented, QBackingStore::beginPaint expects the painted region // Although undocumented, QBackingStore::beginPaint expects the painted region
// to be cleared before use if the window has a surface format with an alpha. // to be cleared before use if the window has a surface format with an alpha.
// Fresh IOSurfaces are already cleared, so we don't need to clear those. // Fresh IOSurfaces are already cleared, so we don't need to clear those.
if (!bufferWasRecreated && window()->format().hasAlpha()) { if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use"; qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage()); QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source); painter.setCompositionMode(QPainter::CompositionMode_Source);
@ -511,9 +511,13 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
if (!prepareForFlush()) if (!prepareForFlush())
return; return;
if (flushedWindow != window()) {
flushSubWindow(flushedWindow);
return;
}
QMacAutoReleasePool pool; QMacAutoReleasePool pool;
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view(); NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may // If the backingstore is just flushed, without being painted to first, then we may
@ -548,7 +552,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// are committed as part of a display-cycle instead of on the next runloop pass. This // are committed as part of a display-cycle instead of on the next runloop pass. This
// means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush // means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
// with other pending view and layer updates. // with other pending view and layer updates.
backingStoreView.window.viewsNeedDisplay = YES; flushedView.window.viewsNeedDisplay = YES;
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) { if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable, // The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
@ -556,28 +560,10 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contents = nil; flushedView.layer.contents = nil;
} }
if (flushedView == backingStoreView) {
qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
<< "to" << flushedView.layer << "of" << flushedView; << "to" << flushedView.layer << "of" << flushedView;
flushedView.layer.contents = backBufferSurface; flushedView.layer.contents = backBufferSurface;
} else {
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
// We make a copy of the image data up front, which means we don't
// need to mark the IOSurface as being in use. FIXME: Investigate
// if there's a cheaper way to get sub-image data to a layer.
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
m_buffers.back()->unlock();
qCInfo(lcQpaBackingStore) << "Flushing" << subImage
<< "to" << flushedView.layer << "of subview" << flushedView;
QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
QCFType<CGImageRef>(subImage.toCGImage()), colorSpace());
flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
}
// Since we may receive multiple flushes before a new frame is started, we do not // Since we may receive multiple flushes before a new frame is started, we do not
// swap any buffers just yet. Instead we check in the next beginPaint if the layer's // swap any buffers just yet. Instead we check in the next beginPaint if the layer's
@ -589,6 +575,53 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server. // the window server.
} }
void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
{
qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
<< "via its own backingstore";
auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
if (!subWindowBackingStore) {
subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
subWindowBackingStore->m_clearSurfaceOnPaint = false;
}
auto subWindowSize = subWindow->size();
static const auto kNoStaticContents = QRegion();
subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
subWindowBackingStore->beginPaint(subWindowLocalRect);
QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
const QImage *backingStoreImage = m_buffers.back()->asImage();
painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
m_buffers.back()->unlock();
painter.end();
subWindowBackingStore->endPaint();
subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
}
void QCALayerBackingStore::windowDestroyed(QObject *object)
{
auto *window = static_cast<QWindow*>(object);
qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
m_subWindowBackingstores.erase(window);
}
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset, void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground) QPlatformTextureList *textures, bool translucentBackground)
@ -722,4 +755,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image; return &m_image;
} }
#include "moc_qcocoabackingstore.cpp"
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -102,6 +102,8 @@ private slots:
void fromCborStreamReaderIODevice(); void fromCborStreamReaderIODevice();
void validation_data(); void validation_data();
void validation(); void validation();
void recursionLimit_data();
void recursionLimit();
void toDiagnosticNotation_data(); void toDiagnosticNotation_data();
void toDiagnosticNotation(); void toDiagnosticNotation();
@ -1720,6 +1722,58 @@ void tst_QCborValue::validation()
} }
} }
void tst_QCborValue::recursionLimit_data()
{
constexpr int RecursionAttempts = 4096;
QTest::addColumn<QByteArray>("data");
QByteArray arrays(RecursionAttempts, char(0x81));
QByteArray _arrays(RecursionAttempts, char(0x9f));
QByteArray maps(RecursionAttempts, char(0xa1));
QByteArray _maps(RecursionAttempts, char(0xbf));
QByteArray tags(RecursionAttempts, char(0xc0));
QTest::newRow("array-nesting-too-deep") << arrays;
QTest::newRow("_array-nesting-too-deep") << _arrays;
QTest::newRow("map-nesting-too-deep") << maps;
QTest::newRow("_map-nesting-too-deep") << _maps;
QTest::newRow("tag-nesting-too-deep") << tags;
QByteArray mixed(5 * RecursionAttempts, Qt::Uninitialized);
char *ptr = mixed.data();
for (int i = 0; i < RecursionAttempts; ++i) {
quint8 type = qBound(quint8(QCborStreamReader::Array), quint8(i & 0x80), quint8(QCborStreamReader::Tag));
quint8 additional_info = i & 0x1f;
if (additional_info == 0x1f)
(void)additional_info; // leave it
else if (additional_info > 0x1a)
additional_info = 0x1a;
else if (additional_info < 1)
additional_info = 1;
*ptr++ = type | additional_info;
if (additional_info == 0x18) {
*ptr++ = uchar(i);
} else if (additional_info == 0x19) {
qToBigEndian(ushort(i), ptr);
ptr += 2;
} else if (additional_info == 0x1a) {
qToBigEndian(uint(i), ptr);
ptr += 4;
}
}
QTest::newRow("mixed-nesting-too-deep") << mixed;
}
void tst_QCborValue::recursionLimit()
{
QFETCH(QByteArray, data);
QCborParserError error;
QCborValue decoded = QCborValue::fromCbor(data, &error);
QCOMPARE(error.error, QCborError::NestingTooDeep);
}
void tst_QCborValue::toDiagnosticNotation_data() void tst_QCborValue::toDiagnosticNotation_data()
{ {
QTest::addColumn<QCborValue>("v"); QTest::addColumn<QCborValue>("v");